package com.sc.nft.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.sc.nft.config.hf.HfConfig;
import com.sc.nft.config.hna.HnaConfig;
import com.sc.nft.config.lianlian.LlConfig;
import com.sc.nft.config.sand.SandConfig;
import com.sc.nft.config.sand.SandPayUtil;
import com.sc.nft.dao.*;
import com.sc.nft.dto.HnaFastPayDTO;
import com.sc.nft.dto.PayOrderPageDTO;
import com.sc.nft.entity.*;
import com.sc.nft.entity.dto.SaasTaskBurialPointDTO;
import com.sc.nft.entity.vo.BalanceVO;
import com.sc.nft.entity.vo.GetPaySignVO;
import com.sc.nft.enums.*;
import com.sc.nft.exception.GlobalException;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.helper.HfPayHelper;
import com.sc.nft.helper.LlPayHelper;
import com.sc.nft.helper.MessageQueueHelper;
import com.sc.nft.helper.SandAccountHelper;
import com.sc.nft.service.*;
import com.sc.nft.sup.ErrorCode;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.sc.nft.config.lianlian.LlConfig.paySuccessNotifyUrl;
import static com.sc.nft.config.sand.SandPayUtil.*;

@Slf4j
@Service
@RequiredArgsConstructor
public class PayOrderServiceImpl implements PayOrderService {

    private final static String dateTimeFormat = "yyyyMMddHHmmss";

    private final static List<String> FAST_ENCODE_FIELD = Lists.newArrayList("mer_key", "goods_name", "notify_url", "return_url", "pay_extra", "meta_option");
    private final OrderService orderService;
    private final PayOrderItemDao payOrderItemDao;
    private final Redisson redisson;
    private final OrderDao orderDao;
    private final RoughStoneOrderDao roughStoneOrderDao;
    @Autowired
    UserHnaExtService userHnaExtService;
    private final RoughStoneOrderService roughStoneOrderService;
    private final SecondOrderDao secondOrderDao;
    private final SecondEquityPropsOrderDao secondEquityPropsOrderDao;
    private final IdcardInfoDao idcardInfoDao;
    private final PayOrderDao payOrderDao;
    private final SandAccountHelper sandAccountHelper;
    private final StaticDataDao staticDataDao;
    private final NewSecondCollectionCommonService newSecondCollectionCommonService;
    private final UserBankCardDao userBankCardDao;
    private final UserWalletService userWalletService;
    private final HnaConfig hnaConfig;
    private final UserHfExtDao userHfExtDao;
    private final MessageQueueHelper messageQueueHelper;
    private final ScrollWantBuyDao scrollWantBuyDao;
    private final CollectiveOrderDao collectiveOrderDao;
    private final CollectiveOrderService collectiveOrderService;
    private final HfPayHelper hfPayHelper;
    private final LlPayHelper llPayHelper;
    private final SecondEquityPropsOrderService secondEquityPropsOrderService;
    private final UserCityServerCentreDao userCityServerCentreDao;
    private final BusinessCardOrderService businessCardOrderService;
    private final BusinessCardOrderDao businessCardOrderDao;
    public static final Snowflake snowflake = new Snowflake();
    private final LlUserExtService llUserExtService;

    @Value("${pay.wallet.wallet_url}")
    private String walletUrl;

    @Value("${pay.hfConfig.secondFrontReturnUrl}")
    private String secondFrontReturnUrl;
    @Value("${pay.hfConfig.daoFrontReturnUrl}")
    private String daoFrontReturnUrl;
    private final UserEquityPropsService userEquityPropsService;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public GetPaySignVO getPay(PayMethodEnum payMethod, Long orderId, Long bankCardId, UserInfo userInfo, String IP, String mac, Boolean webPay, Integer jumpType) {
        Order order = orderDao.getById(orderId);
        Assert.notNull(order, () -> new GlobalRunTimeException(ErrorCode.ORDER_NOT_FOUND));
        Assert.isTrue(order.getUserId().longValue() == userInfo.getId().longValue(), () -> new GlobalRunTimeException(ErrorCode.ORDER_NOT_FOUND));
        Assert.isTrue(order.getStatus() == OrderStatusEnum.WAIT_PAY, () -> new GlobalRunTimeException(ErrorCode.ORDER_STATUS_ERROR));
        IdcardInfo idcardInfo = idcardInfoDao.getByUserIdAndIsPass(userInfo.getId());
        Assert.notNull(idcardInfo, () -> new GlobalRunTimeException(ErrorCode.USER_NOT_SM));
        Assert.isNull(payOrderDao.getPaySuccessByOrderNo(order.getOrderNo()), () -> new GlobalRunTimeException(ErrorCode.ORDER_PAID));
        // 杉德收银台支付的时候，不会重新发起一条，而是会直接告知错误信息订单已存在。所以要查询一下,确定是否存在,同时也要考虑是否过期的问题
        if (payMethod == PayMethodEnum.SAND_BALANCE_PAY) {
            PayOrder byOrderNo = payOrderDao.getByOrderNo(order.getOrderNo());
            if (BeanUtil.isNotEmpty(byOrderNo)) {
                if (byOrderNo.getStatus() == PayStatusEnum.INIT) {
                    GetPaySignVO getPaySignVO = new GetPaySignVO();
                    getPaySignVO.setSign(byOrderNo.getReqResult());
                    getPaySignVO.setId(byOrderNo.getId());
                    getPaySignVO.setOrderNo(order.getOrderNo());
                    getPaySignVO.setPayMethodEnum(payMethod);
                    return getPaySignVO;
                } else {
                    throw new GlobalRunTimeException("订单状态异常，取消后重新下单");
                }
            }
        }
        PayOrder payOrder = new PayOrder();
        DateTime now = DateTime.now();
        payOrder.setPayType(payMethod);
        payOrder.setReqTime(now);
        payOrder.setCloseTime(order.getCloseTime());
        payOrder.setOrderNo(order.getOrderNo());
        payOrder.setReqIp(IP);
        payOrder.setUserCardId(bankCardId);
        payOrder.setUserId(userInfo.getId());
        payOrder.setOrderType(PayTypeEnum.PAY);
        payOrder.setPayAmount(order.getProductPrice());
        payOrder.setRefundAmount(BigDecimal.ZERO);
        payOrder.setChannel(payMethod.getChannel());
        payOrder.setStatus(PayStatusEnum.INIT);
        payOrder.setTradeNo(UUID.fastUUID().toString().replaceAll("-", ""));
        payOrder.setUserId(order.getUserId());
        String sign = null;

        switch (payMethod) {
            case WALLET_PAY:
                break;
            case FAST_PAY: //衫德绑卡
                Assert.notNull(bankCardId, () -> new GlobalRunTimeException("请选择支付银行卡"));
                UserBankCard userBankCard = userBankCardDao.getById(bankCardId);
                Assert.isTrue(ObjectUtil.isNotNull(userBankCard) || userBankCard.getChannel() != PayChannelEnum.SAND, () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                Assert.isTrue(userBankCard.getUserId().longValue() == userInfo.getId().longValue(), () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                payOrder.setNotifyUrl(SandConfig.NOTIFY_URL);
                payOrder.setFrontUrl(SandConfig.FAST_RETURN_URL);
                JSONObject header = getHeader(PAY_SMS_METHOD, BIND_CARD);
                JSONObject body = getSendSmsRequest(userBankCard, userInfo, payOrder.getTradeNo());
                JSONObject result = fastPayRequest(header, body, PAY_SMS_PATH); //这里没错
                payOrder.setReqResult(result.toJSONString());
                if (!StrUtil.equals(result.getJSONObject("head").getString("respCode"), "000000")) {
                    throw new GlobalRunTimeException("发送短信失败：" + result.getJSONObject("head").getString("respMsg"));
                }
                break;
            case LL_PAY:
                Assert.notNull(bankCardId, () -> new GlobalRunTimeException("请选择支付银行卡"));
                userBankCard = userBankCardDao.getById(bankCardId);
                Assert.isTrue(ObjectUtil.isNotNull(userBankCard) || userBankCard.getChannel() != PayChannelEnum.LL_PAY, () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                Assert.isTrue(userBankCard.getUserId().longValue() == userInfo.getId().longValue(), () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                payOrder.setNotifyUrl(paySuccessNotifyUrl);
                payOrder.setFrontUrl(LlConfig.paySuccessReturnUrl + "?jump=page&type=1&orderNo=" + payOrder.getOrderNo());
                payOrder.setUserId(userInfo.getId());
                llPayHelper.createOrder(userInfo, payOrder);
                result = llPayHelper.fastPay(userInfo, order.getFirstTitle(), payOrder, userBankCard);
                payOrder.setReqResult(result.toJSONString());
                sign = result.getString("token");
                break;
            case HNA_PAY:
                Assert.notNull(bankCardId, () -> new GlobalRunTimeException("请选择支付银行卡"));
                userBankCard = userBankCardDao.getById(bankCardId);
                Assert.isTrue(
                        ObjectUtil.isNotNull(userBankCard) || userBankCard.getChannel() != PayChannelEnum.HNA_PAY,
                        () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                Assert.isTrue(
                        userBankCard.getUserId().longValue() == userInfo.getId().longValue(),
                        () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                HnaFastPayDTO dto = new HnaFastPayDTO();
                dto.setPayType("2");
                dto.setPayOrderNo(payOrder.getTradeNo());
                dto.setTranAmount(payOrder.getPayAmount().toPlainString());
                dto.setCardNo(userBankCard.getBankCardNo());
                dto.setIdentityCode(idcardInfo.getCardId());
                dto.setHolderName(idcardInfo.getName());
                dto.setIdentityType("1");
                dto.setMobileNo(userBankCard.getMobile());
                dto.setReceiveUserId(hnaConfig.getMerId());
                payOrder.setNotifyUrl(hnaConfig.getT007NotifyUrl());
                payOrder.setFrontUrl(LlConfig.paySuccessReturnUrl + "?jump=page&type=1&orderNo=" + payOrder.getOrderNo());
                result = userHnaExtService.fastPay(userInfo, dto);
                payOrder.setReqResult(result.toJSONString());
                payOrder.setOutTradeNo(result.getString("ncountOrderId"));
                break;
            case HF_FAST_PAY: //汇付绑卡
                payOrder.setNotifyUrl(HfConfig.notifyUrl);
                if (BooleanUtil.isTrue(webPay)) {
                    StringBuffer frontUrl = new StringBuffer();
                    if (jumpType.intValue() == 1) {
                        frontUrl.append(secondFrontReturnUrl);
                    } else if (jumpType.intValue() == 2) {
                        frontUrl.append(daoFrontReturnUrl);
                    }
                    frontUrl.append("?orderNo=").append(payOrder.getOrderNo()).append("&id=").append(orderId).append("&type=1");
                    payOrder.setFrontUrl(frontUrl.toString());
                } else {
                    payOrder.setFrontUrl(SandConfig.FAST_RETURN_URL);
                }
                IdcardInfo idCard = idcardInfoDao.getByUserIdAndIsPass(payOrder.getUserId());
                JSONObject jsonObject = hfPayHelper.createOrder(orderId, payOrder, order.getFirstTitle(), null, idCard.getCardId(), idCard.getName(), payOrder.getReqIp(), mac, false);
                sign = jsonObject.getString("pay_url");
                payOrder.setReqResult(jsonObject.toJSONString());
                break;
            case SAND_BALANCE_PAY: //衫德余额
                if (!userInfo.getSandAccountOpen()) {
                    throw new GlobalRunTimeException("请先完成开户");
                }
                BalanceVO balance = sandAccountHelper.getBalance(userInfo);
                if (NumberUtil.isGreater(payOrder.getPayAmount(), new BigDecimal(balance.getAvailableBal()))) {
                    throw new GlobalRunTimeException("余额不足");
                }
                payOrder.setNotifyUrl(SandConfig.NOTIFY_URL);
                if (webPay) {
                    StringBuffer frontUrl = new StringBuffer();
                    if (jumpType.intValue() == 1) {
                        frontUrl.append(walletUrl);
                    } else if (jumpType.intValue() == 2) {
                        frontUrl.append(daoFrontReturnUrl);
                    }
                    frontUrl.append("?orderNo=").append(payOrder.getOrderNo()).append("&id=").append(orderId).append("&type=1");
                    payOrder.setFrontUrl(frontUrl.toString());
                } else {
                    payOrder.setFrontUrl(SandConfig.FAST_RETURN_URL);
                }
                sign = SandPayUtil.c2bRequest(getHeader(C2B_METHOD, C2B_PRODUCT_CODE), c2bCreateOrder(payOrder, order.getFirstTitle(), userInfo), "createOrder");
                payOrder.setReqResult(sign);
                break;
            default:
                throw new GlobalRunTimeException("暂不支持该支付方式");
        }
        payOrder.insert();
        GetPaySignVO getPaySignVO = new GetPaySignVO();
        getPaySignVO.setSign(sign);
        getPaySignVO.setId(payOrder.getId());
        getPaySignVO.setOrderNo(order.getOrderNo());
        getPaySignVO.setPayMethodEnum(payMethod);
        return getPaySignVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public GetPaySignVO getPayRough(PayMethodEnum payMethod, Long orderId, Long bankCardId, UserInfo userInfo, String IP, String mac, Boolean webPay, Integer jumpType) {
        RoughStoneOrder order = roughStoneOrderDao.getById(orderId);
        Assert.notNull(order, () -> new GlobalRunTimeException(ErrorCode.ORDER_NOT_FOUND));
        Assert.isTrue(order.getUserId().longValue() == userInfo.getId().longValue(), () -> new GlobalRunTimeException(ErrorCode.ORDER_NOT_FOUND));
        Assert.isTrue(order.getStatus() == OrderStatusEnum.WAIT_PAY, () -> new GlobalRunTimeException(ErrorCode.ORDER_STATUS_ERROR));
        IdcardInfo idcardInfo = idcardInfoDao.getByUserIdAndIsPass(userInfo.getId());
        Assert.notNull(idcardInfo, () -> new GlobalRunTimeException(ErrorCode.USER_NOT_SM));
        Assert.isNull(payOrderDao.getPaySuccessByOrderNo(order.getOrderNo()), () -> new GlobalRunTimeException(ErrorCode.ORDER_PAID));
        // 杉德收银台支付的时候，不会重新发起一条，而是会直接告知错误信息订单已存在。所以要查询一下,确定是否存在,同时也要考虑是否过期的问题
        if (payMethod == PayMethodEnum.SAND_BALANCE_PAY) {
            PayOrder byOrderNo = payOrderDao.getByOrderNo(order.getOrderNo());
            if (BeanUtil.isNotEmpty(byOrderNo)) {
                if (byOrderNo.getStatus() == PayStatusEnum.INIT) {
                    GetPaySignVO getPaySignVO = new GetPaySignVO();
                    getPaySignVO.setSign(byOrderNo.getReqResult());
                    getPaySignVO.setId(byOrderNo.getId());
                    getPaySignVO.setOrderNo(order.getOrderNo());
                    getPaySignVO.setPayMethodEnum(payMethod);
                    return getPaySignVO;
                } else {
                    throw new GlobalRunTimeException("订单状态异常，取消后重新下单");
                }
            }
        }
        PayOrder payOrder = new PayOrder();
        DateTime now = DateTime.now();
        payOrder.setPayType(payMethod);
        payOrder.setReqTime(now);
        payOrder.setUserCardId(bankCardId);
        payOrder.setCloseTime(order.getCloseTime());
        payOrder.setOrderNo(order.getOrderNo());
        payOrder.setReqIp(IP);
        payOrder.setUserId(userInfo.getId());
        payOrder.setOrderType(PayTypeEnum.PAY_SALVAGE);
        payOrder.setPayAmount(order.getProductPrice());
        payOrder.setRefundAmount(BigDecimal.ZERO);
        payOrder.setChannel(payMethod.getChannel());
        payOrder.setStatus(PayStatusEnum.INIT);
        payOrder.setTradeNo(UUID.fastUUID().toString().replaceAll("-", ""));
        payOrder.setUserId(order.getUserId());
        String sign = null;

        switch (payMethod) {
            case FAST_PAY: //衫德绑卡
                Assert.notNull(bankCardId, () -> new GlobalRunTimeException("请选择支付银行卡"));
                UserBankCard userBankCard = userBankCardDao.getById(bankCardId);
                Assert.isTrue(ObjectUtil.isNotNull(userBankCard) || userBankCard.getChannel() != PayChannelEnum.SAND, () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                Assert.isTrue(userBankCard.getUserId().longValue() == userInfo.getId().longValue(), () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                payOrder.setNotifyUrl(SandConfig.NOTIFY_URL);
                payOrder.setFrontUrl(SandConfig.FAST_RETURN_URL);
                JSONObject header = getHeader(PAY_SMS_METHOD, BIND_CARD);
                JSONObject body = getSendSmsRequest(userBankCard, userInfo, payOrder.getTradeNo());
                JSONObject result = fastPayRequest(header, body, PAY_SMS_PATH); //这里没错
                payOrder.setReqResult(result.toJSONString());
                if (!StrUtil.equals(result.getJSONObject("head").getString("respCode"), "000000")) {
                    throw new GlobalRunTimeException("发送短信失败：" + result.getJSONObject("head").getString("respMsg"));
                }
                break;
            case LL_PAY:
                Assert.notNull(bankCardId, () -> new GlobalRunTimeException("请选择支付银行卡"));
                userBankCard = userBankCardDao.getById(bankCardId);
                Assert.isTrue(ObjectUtil.isNotNull(userBankCard) || userBankCard.getChannel() != PayChannelEnum.LL_PAY, () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                Assert.isTrue(userBankCard.getUserId().longValue() == userInfo.getId().longValue(), () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                payOrder.setNotifyUrl(paySuccessNotifyUrl);
                payOrder.setFrontUrl(LlConfig.paySuccessReturnUrl + "?jump=page&type=1&orderNo=" + payOrder.getOrderNo());
                payOrder.setUserId(userInfo.getId());
                llPayHelper.createOrder(userInfo, payOrder);
                result = llPayHelper.fastPay(userInfo, order.getFirstTitle(), payOrder, userBankCard);
                payOrder.setReqResult(result.toJSONString());
                sign = result.getString("token");
                break;
            case HNA_PAY:
                Assert.notNull(bankCardId, () -> new GlobalRunTimeException("请选择支付银行卡"));
                userBankCard = userBankCardDao.getById(bankCardId);
                Assert.isTrue(
                        ObjectUtil.isNotNull(userBankCard) || userBankCard.getChannel() != PayChannelEnum.HNA_PAY,
                        () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                Assert.isTrue(
                        userBankCard.getUserId().longValue() == userInfo.getId().longValue(),
                        () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                HnaFastPayDTO dto = new HnaFastPayDTO();
                dto.setPayOrderNo(payOrder.getTradeNo());
                dto.setTranAmount(payOrder.getPayAmount().toPlainString());
                dto.setPayType("2");
                dto.setCardNo(userBankCard.getBankCardNo());
                dto.setIdentityCode(idcardInfo.getCardId());
                dto.setHolderName(idcardInfo.getName());
                dto.setIdentityType("1");
                dto.setMobileNo(userBankCard.getMobile());
                dto.setReceiveUserId(hnaConfig.getMerId());
                payOrder.setNotifyUrl(hnaConfig.getT007NotifyUrl());
                payOrder.setFrontUrl(LlConfig.paySuccessReturnUrl + "?jump=page&type=1&orderNo=" + payOrder.getOrderNo());
                result = userHnaExtService.fastPay(userInfo, dto);
                payOrder.setReqResult(result.toJSONString());
                payOrder.setOutTradeNo(result.getString("ncountOrderId"));
                break;
            case HF_FAST_PAY: //汇付绑卡
                payOrder.setNotifyUrl(HfConfig.notifyUrl);
                if (BooleanUtil.isTrue(webPay)) {
                    StringBuffer frontUrl = new StringBuffer();
                    if (jumpType.intValue() == 1) {
                        frontUrl.append(secondFrontReturnUrl);
                    } else if (jumpType.intValue() == 2) {
                        frontUrl.append(daoFrontReturnUrl);
                    }
                    frontUrl.append("?orderNo=").append(payOrder.getOrderNo()).append("&id=").append(orderId).append("&type=1");
                    payOrder.setFrontUrl(frontUrl.toString());
                } else {
                    payOrder.setFrontUrl(SandConfig.FAST_RETURN_URL);
                }
                IdcardInfo idCard = idcardInfoDao.getByUserIdAndIsPass(payOrder.getUserId());
                JSONObject jsonObject = hfPayHelper.createOrder(orderId, payOrder, order.getFirstTitle(), null, idCard.getCardId(), idCard.getName(), payOrder.getReqIp(), mac, false);
                sign = jsonObject.getString("pay_url");
                payOrder.setReqResult(jsonObject.toJSONString());
                break;
            case SAND_BALANCE_PAY: //衫德余额
                if (!userInfo.getSandAccountOpen()) {
                    throw new GlobalRunTimeException("请先完成开户");
                }
                BalanceVO balance = sandAccountHelper.getBalance(userInfo);
                if (NumberUtil.isGreater(payOrder.getPayAmount(), new BigDecimal(balance.getAvailableBal()))) {
                    throw new GlobalRunTimeException("余额不足");
                }
                payOrder.setNotifyUrl(SandConfig.NOTIFY_URL);
                if (webPay) {
                    if (jumpType.intValue() == 1) {
                        payOrder.setFrontUrl(walletUrl);
                    } else if (jumpType.intValue() == 2) {
                        payOrder.setFrontUrl(daoFrontReturnUrl);
                    }
                } else {
                    payOrder.setFrontUrl(SandConfig.FAST_RETURN_URL);
                }
                sign = SandPayUtil.c2bRequest(getHeader(C2B_METHOD, C2B_PRODUCT_CODE), c2bCreateOrder(payOrder, order.getFirstTitle(), userInfo), "createOrder");
                payOrder.setReqResult(sign);
                break;
            case BALANCE_ONLY:
                // 仅余额支付能力支撑
                break;
            default:
                throw new GlobalRunTimeException("暂不支持该支付方式");
        }
        payOrder.insert();
        GetPaySignVO getPaySignVO = new GetPaySignVO();
        getPaySignVO.setSign(sign);
        getPaySignVO.setId(payOrder.getId());
        getPaySignVO.setOrderNo(order.getOrderNo());
        getPaySignVO.setPayMethodEnum(payMethod);
        return getPaySignVO;
    }

    @Override
    public GetPaySignVO getPayBusinessCard(PayMethodEnum payMethod, Long orderId, Long bankCardId, UserInfo userInfo, String IP, String mac, Boolean webPay, Integer jumpType) {
        BusinessCardOrder order = businessCardOrderDao.getById(orderId);
        Assert.notNull(order, () -> new GlobalRunTimeException(ErrorCode.ORDER_NOT_FOUND));
        Assert.isTrue(order.getUserId().longValue() == userInfo.getId().longValue(), () -> new GlobalRunTimeException(ErrorCode.ORDER_NOT_FOUND));
        Assert.isTrue(order.getStatus() == OrderStatusEnum.WAIT_PAY, () -> new GlobalRunTimeException(ErrorCode.ORDER_STATUS_ERROR));
        IdcardInfo idcardInfo = idcardInfoDao.getByUserIdAndIsPass(userInfo.getId());
        Assert.notNull(idcardInfo, () -> new GlobalRunTimeException(ErrorCode.USER_NOT_SM));
        Assert.isNull(payOrderDao.getPaySuccessByOrderNo(order.getOrderNo()), () -> new GlobalRunTimeException(ErrorCode.ORDER_PAID));
        // 杉德收银台支付的时候，不会重新发起一条，而是会直接告知错误信息订单已存在。所以要查询一下,确定是否存在,同时也要考虑是否过期的问题
        if (payMethod == PayMethodEnum.SAND_BALANCE_PAY) {
            PayOrder byOrderNo = payOrderDao.getByOrderNo(order.getOrderNo());
            if (BeanUtil.isNotEmpty(byOrderNo)) {
                if (byOrderNo.getStatus() == PayStatusEnum.INIT) {
                    GetPaySignVO getPaySignVO = new GetPaySignVO();
                    getPaySignVO.setSign(byOrderNo.getReqResult());
                    getPaySignVO.setId(byOrderNo.getId());
                    getPaySignVO.setOrderNo(order.getOrderNo());
                    getPaySignVO.setPayMethodEnum(payMethod);
                    return getPaySignVO;
                } else {
                    throw new GlobalRunTimeException("订单状态异常，取消后重新下单");
                }
            }
        }
        PayOrder payOrder = new PayOrder();
        DateTime now = DateTime.now();
        payOrder.setPayType(payMethod);
        payOrder.setReqTime(now);
        payOrder.setUserCardId(bankCardId);
        payOrder.setCloseTime(order.getCloseTime());
        payOrder.setOrderNo(order.getOrderNo());
        payOrder.setReqIp(IP);
        payOrder.setUserId(userInfo.getId());
        payOrder.setOrderType(PayTypeEnum.BUSINESS_CARD);
        payOrder.setPayAmount(order.getBuyPrice());
        payOrder.setRefundAmount(BigDecimal.ZERO);
        payOrder.setChannel(payMethod.getChannel());
        payOrder.setStatus(PayStatusEnum.INIT);
        payOrder.setTradeNo(UUID.fastUUID().toString().replaceAll("-", ""));
        payOrder.setUserId(order.getUserId());
        String sign = null;

        switch (payMethod) {
            case WALLET_PAY:
                break;
            case FAST_PAY:
                Assert.notNull(bankCardId, () -> new GlobalRunTimeException("请选择支付银行卡"));
                UserBankCard userBankCard = userBankCardDao.getById(bankCardId);
                Assert.isTrue(ObjectUtil.isNotNull(userBankCard) || userBankCard.getChannel() != PayChannelEnum.SAND, () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                Assert.isTrue(userBankCard.getUserId().longValue() == userInfo.getId().longValue(), () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                payOrder.setNotifyUrl(SandConfig.NOTIFY_URL);
                payOrder.setFrontUrl(SandConfig.FAST_RETURN_URL);
                payOrder.setUserId(userInfo.getId());
                JSONObject header = getHeader(PAY_SMS_METHOD, BIND_CARD);
                JSONObject body = getSendSmsRequest(userBankCard, userInfo, payOrder.getTradeNo());
                JSONObject result = fastPayRequest(header, body, PAY_SMS_PATH);
                payOrder.setReqResult(result.toJSONString());
                if (!StrUtil.equals(result.getJSONObject("head").getString("respCode"), "000000")) {
                    throw new GlobalRunTimeException("发送短信失败：" + result.getJSONObject("head").getString("respMsg"));
                }
                break;
            case LL_PAY:
                Assert.notNull(bankCardId, () -> new GlobalRunTimeException("请选择支付银行卡"));
                userBankCard = userBankCardDao.getById(bankCardId);
                Assert.isTrue(ObjectUtil.isNotNull(userBankCard) || userBankCard.getChannel() != PayChannelEnum.LL_PAY, () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                Assert.isTrue(userBankCard.getUserId().longValue() == userInfo.getId().longValue(), () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                payOrder.setNotifyUrl(paySuccessNotifyUrl);
                payOrder.setFrontUrl(LlConfig.paySuccessReturnUrl + "?jump=page&type=1&orderNo=" + payOrder.getOrderNo());
                payOrder.setUserId(userInfo.getId());
                llPayHelper.createOrder(userInfo, payOrder);
                result = llPayHelper.fastPay(userInfo, "元宇宙名片购买", payOrder, userBankCard);
                payOrder.setReqResult(result.toJSONString());
                sign = result.getString("token");
                break;
            case HNA_PAY:
                Assert.notNull(bankCardId, () -> new GlobalRunTimeException("请选择支付银行卡"));
                userBankCard = userBankCardDao.getById(bankCardId);
                Assert.isTrue(
                        ObjectUtil.isNotNull(userBankCard) || userBankCard.getChannel() != PayChannelEnum.HNA_PAY,
                        () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                Assert.isTrue(
                        userBankCard.getUserId().longValue() == userInfo.getId().longValue(),
                        () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                HnaFastPayDTO dto = new HnaFastPayDTO();
                dto.setPayOrderNo(payOrder.getTradeNo());
                dto.setTranAmount(payOrder.getPayAmount().toPlainString());
                dto.setPayType("2");
                dto.setCardNo(userBankCard.getBankCardNo());
                dto.setIdentityCode(idcardInfo.getCardId());
                dto.setHolderName(idcardInfo.getName());
                dto.setIdentityType("1");
                dto.setMobileNo(userBankCard.getMobile());
                dto.setReceiveUserId(hnaConfig.getMerId());
                payOrder.setNotifyUrl(hnaConfig.getT007NotifyUrl());
                payOrder.setFrontUrl(LlConfig.paySuccessReturnUrl + "?jump=page&type=1&orderNo=" + payOrder.getOrderNo());
                result = userHnaExtService.fastPay(userInfo, dto);
                payOrder.setReqResult(result.toJSONString());
                payOrder.setOutTradeNo(result.getString("ncountOrderId"));
                break;
            case HF_FAST_PAY:
                payOrder.setNotifyUrl(HfConfig.notifyUrl);
                if (BooleanUtil.isTrue(webPay)) {
                    StringBuffer frontUrl = new StringBuffer();
                    frontUrl.append(secondFrontReturnUrl);
                    frontUrl.append("?type=4&");
                    frontUrl.append("orderNo=").append(payOrder.getOrderNo());
                    payOrder.setFrontUrl(frontUrl.toString());
                } else {
                    payOrder.setFrontUrl(SandConfig.FAST_RETURN_URL);
                }
                IdcardInfo idCard = idcardInfoDao.getByUserIdAndIsPass(payOrder.getUserId());
                UserHfExt hfExt = userHfExtDao.findByUserId(userInfo.getId());
                Assert.isTrue(ObjectUtil.isNotNull(hfExt) && hfExt.getStatus() == AccountStatusEnum.SUCCESS, () -> new GlobalRunTimeException("请先完成汇付开户"));
                JSONObject jsonObject = hfPayHelper.createOrder(null, payOrder, "元宇宙名片购买", hfExt.getUserCustId(), idCard.getCardId(), idCard.getName(), payOrder.getReqIp(), mac, true);
                sign = jsonObject.getString("pay_url");
                payOrder.setReqResult(jsonObject.toJSONString());
                break;
            case SAND_BALANCE_PAY:
                if (!userInfo.getSandAccountOpen()) {
                    throw new GlobalRunTimeException("请先完成开户");
                }
                BalanceVO balance = sandAccountHelper.getBalance(userInfo);
                if (NumberUtil.isGreater(payOrder.getPayAmount(), new BigDecimal(balance.getAvailableBal()))) {
                    throw new GlobalRunTimeException("余额不足");
                }
                payOrder.setNotifyUrl(SandConfig.NOTIFY_URL);
                if (webPay) {
                    payOrder.setFrontUrl(walletUrl);
                } else {
                    payOrder.setFrontUrl(SandConfig.FAST_RETURN_URL);
                }
                sign = SandPayUtil.c2bRequest(getHeader(C2B_METHOD, C2B_PRODUCT_CODE), c2bCreateOrder(payOrder, "元宇宙名片购买", userInfo), "createOrder");
                payOrder.setReqResult(sign);
                break;
            default:
                throw new GlobalRunTimeException("暂不支持该支付方式");

        }
        payOrder.insert();
        GetPaySignVO getPaySignVO = new GetPaySignVO();
        getPaySignVO.setSign(sign);
        getPaySignVO.setId(payOrder.getId());
        getPaySignVO.setOrderNo(order.getOrderNo());
        getPaySignVO.setPayMethodEnum(payMethod);
        return getPaySignVO;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public GetPaySignVO getPaySecond(PayMethodEnum payMethod, List<Long> orderIds, Long bankCardId, UserInfo userInfo,
                                     String IP, String mac, Boolean webPay, String password, String randomKey) {

        List<SecondOrder> secondOrders = secondOrderDao.listByIds(orderIds);
        Assert.notEmpty(secondOrders, () -> new GlobalRunTimeException(ErrorCode.ORDER_NOT_FOUND));
        Assert.isTrue(secondOrders.size() == orderIds.size(), () -> new GlobalRunTimeException("支付订单数量不一致"));
        Date firstTime = new Date();
        BigDecimal sumAmount = BigDecimal.ZERO;
        for (SecondOrder secondOrder : secondOrders) {
            Assert.isTrue(secondOrder.getBuyUserId().longValue() == userInfo.getId().longValue(), () -> new GlobalRunTimeException(ErrorCode.ORDER_NOT_FOUND));
            Assert.isTrue(secondOrder.getStatus() == OrderStatusEnum.WAIT_PAY, () -> new GlobalRunTimeException(ErrorCode.ORDER_STATUS_ERROR));
            if (firstTime.after(secondOrder.getCreateTime())) {
                firstTime = secondOrder.getCreateTime();
            }
            sumAmount = sumAmount.add(secondOrder.getBuyPrice());
        }
        IdcardInfo idcardInfo = idcardInfoDao.getByUserIdAndIsPass(userInfo.getId());
        Assert.notNull(idcardInfo, () -> new GlobalRunTimeException(ErrorCode.USER_NOT_SM));
        Assert.isNull(payOrderDao.getPaySuccessByOrderNo(secondOrders.get(0).getOrderNo()), () -> new GlobalRunTimeException(ErrorCode.ORDER_PAID));
        // 杉德收银台支付的时候，不会重新发起一条，而是会直接告知错误信息订单已存在。所以要查询一下,确定是否存在,同时也要考虑是否过期的问题
        if (payMethod == PayMethodEnum.SAND_BALANCE_PAY) {
            PayOrder byOrderNo = payOrderDao.getByOrderNo(secondOrders.get(0).getOrderNo());
            if (BeanUtil.isNotEmpty(byOrderNo)) {
                if (byOrderNo.getStatus() == PayStatusEnum.INIT) {
                    GetPaySignVO getPaySignVO = new GetPaySignVO();
                    getPaySignVO.setSign(byOrderNo.getReqResult());
                    getPaySignVO.setId(byOrderNo.getId());
                    getPaySignVO.setOrderNo(secondOrders.get(0).getOrderNo());
                    getPaySignVO.setPayMethodEnum(payMethod);
                    return getPaySignVO;
                } else {
                    throw new GlobalRunTimeException("订单状态异常，取消后重新下单");
                }
            }
        }
        PayOrder payOrder = new PayOrder();
        DateTime now = DateTime.now();
        payOrder.setPayType(payMethod);
        payOrder.setReqTime(now);
        payOrder.setCloseTime(DateUtil.offsetMinute(firstTime, 3));
        payOrder.setOrderNo(secondOrders.get(0).getOrderNo());
        payOrder.setReqIp(IP);
        payOrder.setUserId(userInfo.getId());
        payOrder.setOrderType(PayTypeEnum.SECOND);
        payOrder.setPayAmount(sumAmount);
        payOrder.setRefundAmount(BigDecimal.ZERO);
        payOrder.setChannel(payMethod.getChannel());
        payOrder.setStatus(PayStatusEnum.INIT);
        payOrder.setUserCardId(bankCardId);
        payOrder.setTradeNo(UUID.fastUUID().toString().replaceAll("-", ""));
        payOrder.setUserId(userInfo.getId());
        String sign = null;

        switch (payMethod) {
            case WALLET_PAY:
                break;
            case FAST_PAY:
                Assert.notNull(bankCardId, () -> new GlobalRunTimeException("请选择支付银行卡"));
                UserBankCard userBankCard = userBankCardDao.getById(bankCardId);
                Assert.isTrue(ObjectUtil.isNotNull(userBankCard) || userBankCard.getChannel() != PayChannelEnum.SAND, () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                Assert.isTrue(userBankCard.getUserId().longValue() == userInfo.getId().longValue(), () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                payOrder.setNotifyUrl(SandConfig.NOTIFY_URL);
                payOrder.setFrontUrl(SandConfig.FAST_RETURN_URL);
                payOrder.setUserId(userInfo.getId());
                JSONObject header = getHeader(PAY_SMS_METHOD, BIND_CARD);
                JSONObject body = getSendSmsRequest(userBankCard, userInfo, payOrder.getTradeNo());
                JSONObject result = fastPayRequest(header, body, PAY_SMS_PATH);
                payOrder.setReqResult(result.toJSONString());
                if (!StrUtil.equals(result.getJSONObject("head").getString("respCode"), "000000")) {
                    throw new GlobalRunTimeException("发送短信失败：" + result.getJSONObject("head").getString("respMsg"));
                }
                break;
            case LL_PAY:
                Assert.notNull(bankCardId, () -> new GlobalRunTimeException("请选择支付银行卡"));
                userBankCard = userBankCardDao.getById(bankCardId);
                Assert.isTrue(ObjectUtil.isNotNull(userBankCard) || userBankCard.getChannel() != PayChannelEnum.LL_PAY, () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                Assert.isTrue(userBankCard.getUserId().longValue() == userInfo.getId().longValue(), () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                payOrder.setNotifyUrl(paySuccessNotifyUrl);
                payOrder.setFrontUrl(LlConfig.paySuccessReturnUrl + "?jump=page&type=1&orderNo=" + payOrder.getOrderNo());
                payOrder.setUserId(userInfo.getId());
                //二级市场c2c使用担保交易避免二清
                llPayHelper.createOrderForSecuredConsume(userInfo, payOrder, null, PayMethodEnum.LL_PAY);
                result = llPayHelper.fastPay(userInfo, secondOrders.get(0).getFirstTitle() + "*" + secondOrders.size(), payOrder, userBankCard);
                payOrder.setReqResult(result.toJSONString());
                sign = result.getString("token");
                break;
            case LL_BALANCE_PAY:
                LlUserExt userExt = llUserExtService.getByUserId(userInfo.getId());
                Assert.isTrue(ObjectUtil.isNotNull(userExt) && userExt.getStatus() == AccountStatusEnum.SUCCESS, () -> new GlobalRunTimeException("请先完成连连开户"));
                Assert.notNull(password, () -> new GlobalRunTimeException("连连钱包密码不能为空"));
                payOrder.setNotifyUrl(paySuccessNotifyUrl);
                payOrder.setFrontUrl(LlConfig.paySuccessReturnUrl + "?jump=page&type=1&orderNo=" + payOrder.getOrderNo());
                payOrder.setUserId(userInfo.getId());
                //二级市场c2c使用担保交易避免二清
                llPayHelper.createOrderForSecuredConsume(userInfo, payOrder, userExt, PayMethodEnum.LL_BALANCE_PAY);
                result = llPayHelper.balancePay(userInfo, secondOrders.get(0).getFirstTitle() + "*" + secondOrders.size()
                        , payOrder, password, userExt, idcardInfo, randomKey);
                payOrder.setReqResult(result.toJSONString());
                sign = result.getString("token");
                break;
            case HNA_PAY:
                Assert.notNull(bankCardId, () -> new GlobalRunTimeException("请选择支付银行卡"));
                userBankCard = userBankCardDao.getById(bankCardId);
                Assert.isTrue(
                        ObjectUtil.isNotNull(userBankCard) || userBankCard.getChannel() != PayChannelEnum.HNA_PAY,
                        () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                Assert.isTrue(
                        userBankCard.getUserId().longValue() == userInfo.getId().longValue(),
                        () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                HnaFastPayDTO dto = new HnaFastPayDTO();
                dto.setPayOrderNo(payOrder.getTradeNo());
                dto.setTranAmount(payOrder.getPayAmount().toPlainString());
                dto.setPayType("2");
                dto.setCardNo(userBankCard.getBankCardNo());
                dto.setIdentityCode(idcardInfo.getCardId());
                dto.setHolderName(idcardInfo.getName());
                dto.setIdentityType("1");
                dto.setMobileNo(userBankCard.getMobile());
                dto.setReceiveUserId(hnaConfig.getMerId());
                payOrder.setNotifyUrl(hnaConfig.getT007NotifyUrl());
                payOrder.setFrontUrl(LlConfig.paySuccessReturnUrl + "?jump=page&type=1&orderNo=" + payOrder.getOrderNo());
                result = userHnaExtService.fastPay(userInfo, dto);
                payOrder.setReqResult(result.toJSONString());
                payOrder.setOutTradeNo(result.getString("ncountOrderId"));
                break;
            case HF_FAST_PAY:
                payOrder.setNotifyUrl(HfConfig.notifyUrl);
                if (BooleanUtil.isTrue(webPay)) {
                    StringBuffer frontUrl = new StringBuffer();
                    frontUrl.append(secondFrontReturnUrl);
                    frontUrl.append("?type=4&");
                    frontUrl.append("orderNo=").append(payOrder.getOrderNo());
                    payOrder.setFrontUrl(frontUrl.toString());
                } else {
                    payOrder.setFrontUrl(SandConfig.FAST_RETURN_URL);
                }
                IdcardInfo idCard = idcardInfoDao.getByUserIdAndIsPass(payOrder.getUserId());
                UserHfExt hfExt = userHfExtDao.findByUserId(userInfo.getId());
                Assert.isTrue(ObjectUtil.isNotNull(hfExt) && hfExt.getStatus() == AccountStatusEnum.SUCCESS, () -> new GlobalRunTimeException("请先完成汇付开户"));
                JSONObject jsonObject = hfPayHelper.createOrder(null, payOrder, secondOrders.get(0).getFirstTitle(), hfExt.getUserCustId(), idCard.getCardId(), idCard.getName(), payOrder.getReqIp(), mac, true);
                sign = jsonObject.getString("pay_url");
                payOrder.setReqResult(jsonObject.toJSONString());
                break;
            case SAND_BALANCE_PAY:
                if (!userInfo.getSandAccountOpen()) {
                    throw new GlobalRunTimeException("请先完成开户");
                }
                BalanceVO balance = sandAccountHelper.getBalance(userInfo);
                if (NumberUtil.isGreater(payOrder.getPayAmount(), new BigDecimal(balance.getAvailableBal()))) {
                    throw new GlobalRunTimeException("余额不足");
                }
                payOrder.setNotifyUrl(SandConfig.NOTIFY_URL);
                if (webPay) {
                    payOrder.setFrontUrl(walletUrl);
                } else {
                    payOrder.setFrontUrl(SandConfig.FAST_RETURN_URL);
                }
                sign = SandPayUtil.c2bRequest(getHeader(C2B_METHOD, C2B_PRODUCT_CODE), c2bCreateOrder(payOrder, secondOrders.get(0).getFirstTitle(), userInfo), "createOrder");
                payOrder.setReqResult(sign);
                break;
            default:
                throw new GlobalRunTimeException("暂不支持该支付方式");

        }
        payOrder.insert();
        for (SecondOrder secondOrder : secondOrders) {
            PayOrderItem payOrderItem = new PayOrderItem();
            payOrderItem.setPayOrderId(payOrder.getId());
            payOrderItem.setOrderId(secondOrder.getId());
            payOrderItem.setOrderType(SecondPayOrderItemTypeEnum.COLLECTION);
            payOrderItem.setAmount(secondOrder.getBuyPrice());
            payOrderItem.insert();
        }
        GetPaySignVO getPaySignVO = new GetPaySignVO();
        getPaySignVO.setSign(sign);
        getPaySignVO.setId(payOrder.getId());
        getPaySignVO.setOrderNo(secondOrders.get(0).getOrderNo());
        getPaySignVO.setPayMethodEnum(payMethod);
        return getPaySignVO;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public GetPaySignVO getPayProps(PayMethodEnum payMethod, List<Long> orderIds, Long bankCardId, UserInfo userInfo,
                                    String IP, String mac, Boolean webPay, String password, String randomKey) {

        List<SecondEquityPropsOrder> secondOrders = secondEquityPropsOrderDao.listByIds(orderIds);
        Assert.notEmpty(secondOrders, () -> new GlobalRunTimeException(ErrorCode.ORDER_NOT_FOUND));
        Assert.isTrue(secondOrders.size() == orderIds.size(), () -> new GlobalRunTimeException("支付订单数量不一致"));
        IdcardInfo idcardInfo = idcardInfoDao.getByUserIdAndIsPass(userInfo.getId());
        Assert.notNull(idcardInfo, () -> new GlobalRunTimeException(ErrorCode.USER_NOT_SM));
        Date firstTime = new Date();
        BigDecimal sumAmount = BigDecimal.ZERO;
        for (SecondEquityPropsOrder secondOrder : secondOrders) {
            Assert.isTrue(secondOrder.getStatus() == OrderStatusEnum.WAIT_PAY, () -> new GlobalRunTimeException(ErrorCode.ORDER_STATUS_ERROR));
            if (firstTime.after(secondOrder.getCreateTime())) {
                firstTime = secondOrder.getCreateTime();
            }
            sumAmount = sumAmount.add(secondOrder.getBuyPrice());
        }
        Assert.isNull(payOrderDao.getPaySuccessByOrderNo(secondOrders.get(0).getOrderNo()), () -> new GlobalRunTimeException(ErrorCode.ORDER_PAID));
        // 杉德收银台支付的时候，不会重新发起一条，而是会直接告知错误信息订单已存在。所以要查询一下,确定是否存在,同时也要考虑是否过期的问题
        if (payMethod == PayMethodEnum.SAND_BALANCE_PAY) {
            PayOrder byOrderNo = payOrderDao.getByOrderNo(secondOrders.get(0).getOrderNo());
            if (BeanUtil.isNotEmpty(byOrderNo)) {
                if (byOrderNo.getStatus() == PayStatusEnum.INIT) {
                    GetPaySignVO getPaySignVO = new GetPaySignVO();
                    getPaySignVO.setSign(byOrderNo.getReqResult());
                    getPaySignVO.setId(byOrderNo.getId());
                    getPaySignVO.setOrderNo(secondOrders.get(0).getOrderNo());
                    getPaySignVO.setPayMethodEnum(payMethod);
                    return getPaySignVO;
                } else {
                    throw new GlobalRunTimeException("订单状态异常，取消后重新下单");
                }
            }
        }
        PayOrder payOrder = new PayOrder();
        DateTime now = DateTime.now();
        payOrder.setPayType(payMethod);
        payOrder.setReqTime(now);
        payOrder.setUserCardId(bankCardId);
        payOrder.setCloseTime(DateUtil.offsetMinute(firstTime, 3));
        payOrder.setOrderNo(secondOrders.get(0).getOrderNo());
        payOrder.setReqIp(IP);
        payOrder.setUserId(userInfo.getId());
        payOrder.setOrderType(PayTypeEnum.SECOND_EQUITY_PROPS);
        payOrder.setPayAmount(sumAmount);
        payOrder.setRefundAmount(BigDecimal.ZERO);
        payOrder.setChannel(payMethod.getChannel());
        payOrder.setStatus(PayStatusEnum.INIT);
        payOrder.setTradeNo(UUID.fastUUID().toString().replaceAll("-", ""));
        payOrder.setUserId(userInfo.getId());
        String sign = null;


        switch (payMethod) {
            case WALLET_PAY:
                break;
            case FAST_PAY:
                Assert.notNull(bankCardId, () -> new GlobalRunTimeException("请选择支付银行卡"));
                UserBankCard userBankCard = userBankCardDao.getById(bankCardId);
                Assert.isTrue(ObjectUtil.isNotNull(userBankCard) || userBankCard.getChannel() != PayChannelEnum.SAND, () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                Assert.isTrue(userBankCard.getUserId().longValue() == userInfo.getId().longValue(), () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                payOrder.setNotifyUrl(SandConfig.NOTIFY_URL);
                payOrder.setFrontUrl(SandConfig.FAST_RETURN_URL);
                payOrder.setUserId(userInfo.getId());
                JSONObject header = getHeader(PAY_SMS_METHOD, BIND_CARD);
                JSONObject body = getSendSmsRequest(userBankCard, userInfo, payOrder.getTradeNo());
                JSONObject result = fastPayRequest(header, body, PAY_SMS_PATH);
                payOrder.setReqResult(result.toJSONString());
                if (!StrUtil.equals(result.getJSONObject("head").getString("respCode"), "000000")) {
                    throw new GlobalRunTimeException("发送短信失败：" + result.getJSONObject("head").getString("respMsg"));
                }
                break;
            case LL_PAY:
                Assert.notNull(bankCardId, () -> new GlobalRunTimeException("请选择支付银行卡"));
                userBankCard = userBankCardDao.getById(bankCardId);
                Assert.isTrue(ObjectUtil.isNotNull(userBankCard) || userBankCard.getChannel() != PayChannelEnum.LL_PAY, () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                Assert.isTrue(userBankCard.getUserId().longValue() == userInfo.getId().longValue(), () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                payOrder.setNotifyUrl(paySuccessNotifyUrl);
                payOrder.setFrontUrl(LlConfig.paySuccessReturnUrl + "?jump=page&type=1&orderNo=" + payOrder.getOrderNo());
                payOrder.setUserId(userInfo.getId());
                //担保交易
                llPayHelper.createOrderForSecuredConsume(userInfo, payOrder, null, PayMethodEnum.LL_PAY);
                result = llPayHelper.fastPay(userInfo, secondOrders.get(0).getFirstTitle() + "*" + secondOrders.size(), payOrder, userBankCard);
                payOrder.setReqResult(result.toJSONString());
                sign = result.getString("token");
                break;
            case LL_BALANCE_PAY:
                LlUserExt userExt = llUserExtService.getByUserId(userInfo.getId());
                Assert.isTrue(ObjectUtil.isNotNull(userExt) && userExt.getStatus() == AccountStatusEnum.SUCCESS, () -> new GlobalRunTimeException("请先完成连连开户"));
                Assert.notNull(password, () -> new GlobalRunTimeException("连连钱包密码不能为空"));
                payOrder.setNotifyUrl(paySuccessNotifyUrl);
                payOrder.setFrontUrl(LlConfig.paySuccessReturnUrl + "?jump=page&type=1&orderNo=" + payOrder.getOrderNo());
                payOrder.setUserId(userInfo.getId());
                //二级市场c2c使用担保交易避免二清
                llPayHelper.createOrderForSecuredConsume(userInfo, payOrder, userExt, PayMethodEnum.LL_BALANCE_PAY);
                result = llPayHelper.balancePay(userInfo, secondOrders.get(0).getFirstTitle() + "*" + secondOrders.size()
                        , payOrder, password, userExt, idcardInfo, randomKey);
                payOrder.setReqResult(result.toJSONString());
                sign = result.getString("token");
                break;
            case HNA_PAY:
                Assert.notNull(bankCardId, () -> new GlobalRunTimeException("请选择支付银行卡"));
                userBankCard = userBankCardDao.getById(bankCardId);
                Assert.isTrue(
                        ObjectUtil.isNotNull(userBankCard) || userBankCard.getChannel() != PayChannelEnum.HNA_PAY,
                        () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                Assert.isTrue(
                        userBankCard.getUserId().longValue() == userInfo.getId().longValue(),
                        () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                HnaFastPayDTO dto = new HnaFastPayDTO();
                dto.setPayOrderNo(payOrder.getTradeNo());
                dto.setTranAmount(payOrder.getPayAmount().toPlainString());
                dto.setPayType("2");
                dto.setCardNo(userBankCard.getBankCardNo());
                dto.setIdentityCode(idcardInfo.getCardId());
                dto.setHolderName(idcardInfo.getName());
                dto.setIdentityType("1");
                dto.setMobileNo(userBankCard.getMobile());
                dto.setReceiveUserId(hnaConfig.getMerId());
                payOrder.setNotifyUrl(hnaConfig.getT007NotifyUrl());
                payOrder.setFrontUrl(LlConfig.paySuccessReturnUrl + "?jump=page&type=1&orderNo=" + payOrder.getOrderNo());
                result = userHnaExtService.fastPay(userInfo, dto);
                payOrder.setReqResult(result.toJSONString());
                payOrder.setOutTradeNo(result.getString("ncountOrderId"));
                break;
            case HF_FAST_PAY:
                payOrder.setNotifyUrl(HfConfig.notifyUrl);
                if (BooleanUtil.isTrue(webPay)) {
                    StringBuffer frontUrl = new StringBuffer();
                    frontUrl.append(secondFrontReturnUrl);
                    frontUrl.append("?type=5&");
                    frontUrl.append("orderNo=").append(payOrder.getOrderNo());
                    payOrder.setFrontUrl(frontUrl.toString());

                } else {
                    payOrder.setFrontUrl(SandConfig.FAST_RETURN_URL);
                }
                IdcardInfo idCard = idcardInfoDao.getByUserIdAndIsPass(payOrder.getUserId());
                UserHfExt hfExt = userHfExtDao.findByUserId(userInfo.getId());
                Assert.isTrue(ObjectUtil.isNotNull(hfExt) && hfExt.getStatus() == AccountStatusEnum.SUCCESS, () -> new GlobalRunTimeException("请先完成汇付开户"));
                JSONObject jsonObject = hfPayHelper.createOrder(null, payOrder, secondOrders.get(0).getFirstTitle(), hfExt.getUserCustId(), idCard.getCardId(), idCard.getName(), payOrder.getReqIp(), mac, true);
                sign = jsonObject.getString("pay_url");
                payOrder.setReqResult(jsonObject.toJSONString());
                break;
            case SAND_BALANCE_PAY:
                if (!userInfo.getSandAccountOpen()) {
                    throw new GlobalRunTimeException("请先完成开户");
                }
                BalanceVO balance = sandAccountHelper.getBalance(userInfo);
                if (NumberUtil.isGreater(payOrder.getPayAmount(), new BigDecimal(balance.getAvailableBal()))) {
                    throw new GlobalRunTimeException("余额不足");
                }
                payOrder.setNotifyUrl(SandConfig.NOTIFY_URL);
                if (webPay) {
                    payOrder.setFrontUrl(walletUrl);
                } else {
                    payOrder.setFrontUrl(SandConfig.FAST_RETURN_URL);
                }
                sign = SandPayUtil.c2bRequest(getHeader(C2B_METHOD, C2B_PRODUCT_CODE), c2bCreateOrder(payOrder, secondOrders.get(0).getFirstTitle(), userInfo), "createOrder");
                payOrder.setReqResult(sign);
                break;
            default:
                throw new GlobalRunTimeException("暂不支持该支付方式");

        }
        payOrder.insert();
        for (SecondEquityPropsOrder secondOrder : secondOrders) {
            PayOrderItem payOrderItem = new PayOrderItem();
            payOrderItem.setPayOrderId(payOrder.getId());
            payOrderItem.setOrderId(secondOrder.getId());
            payOrderItem.setOrderType(SecondPayOrderItemTypeEnum.EQUITY_PROPS);
            payOrderItem.setAmount(secondOrder.getBuyPrice());
            payOrderItem.insert();
        }
        GetPaySignVO getPaySignVO = new GetPaySignVO();
        getPaySignVO.setSign(sign);
        getPaySignVO.setOrderNo(secondOrders.get(0).getOrderNo());
        getPaySignVO.setPayMethodEnum(payMethod);
        getPaySignVO.setId(payOrder.getId());
        return getPaySignVO;
    }


    @Override
    public void llPayVerify(UserInfo userInfo, Long id, String token, String smsCode) {
        Assert.notBlank(token, () -> new GlobalRunTimeException("token不能为空"));
        Assert.notBlank(smsCode, () -> new GlobalRunTimeException("请填写验证码"));
        PayOrder payOrder = payOrderDao.getById(id);
        Assert.isTrue(ObjectUtil.isNotNull(payOrder) || (payOrder.getPayType() != PayMethodEnum.LL_PAY
                && payOrder.getPayType() != PayMethodEnum.LL_BALANCE_PAY), () -> new GlobalRunTimeException("未找到支付订单"));
        Assert.isTrue(payOrder.getStatus() == PayStatusEnum.INIT, () -> new GlobalRunTimeException("订单已支付"));
        LlUserExt userExt = llUserExtService.getByUserId(userInfo.getId());
        llPayHelper.verifySmsCode(userInfo, payOrder.getTradeNo(), payOrder.getPayAmount(), token, smsCode, userExt, payOrder.getPayType());
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public String HfOpenAccount(UserInfo userInfo, Boolean isWeb) {
        UserHfExt userHfExt = userHfExtDao.findByUserId(userInfo.getId());
        if (ObjectUtil.isNull(userHfExt)) {
            userHfExt = new UserHfExt();
            userHfExt.setUserId(userInfo.getId());
            userHfExt.setHfUserKey(snowflake.nextIdStr());
            userHfExt.setStatus(AccountStatusEnum.OPENING);
            userHfExt.insert();
        }
        Assert.isFalse(userHfExt.getStatus() == AccountStatusEnum.SUCCESS, () -> new GlobalRunTimeException("您已经完成开户"));
        IdcardInfo idInfo = idcardInfoDao.getByUserIdAndIsPass(userInfo.getId());
        Assert.notNull(idInfo, () -> new GlobalRunTimeException(ErrorCode.USER_NOT_SM));
        JSONObject result = hfPayHelper.openAccount(userHfExt, idInfo.getName(), idInfo.getCardId(), userInfo.getUserTel(), isWeb);
        return result.getString("redirect_url");
    }

    @Override
    public String HfWallet(UserInfo userInfo, Boolean isWeb) {
        UserHfExt userHfExt = userHfExtDao.findByUserId(userInfo.getId());
        if (ObjectUtil.isNull(userHfExt) || userHfExt.getStatus() != AccountStatusEnum.SUCCESS) {
            throw new GlobalRunTimeException("汇付钱包尚未开户完成");
        }
        IdcardInfo idInfo = idcardInfoDao.getByUserIdAndIsPass(userInfo.getId());
        Assert.notNull(idInfo, () -> new GlobalRunTimeException("请先完成实名认证"));
        JSONObject result = hfPayHelper.getWallet(userHfExt, isWeb);
        return result.getString("redirect_url");
    }

    @Override
    public JSONObject HfBalance(UserInfo userInfo) {
        UserHfExt userHfExt = userHfExtDao.findByUserId(userInfo.getId());
        if (ObjectUtil.isNull(userHfExt) || userHfExt.getStatus() != AccountStatusEnum.SUCCESS) {
            throw new GlobalRunTimeException("汇付钱包尚未开户完成");
        }
        JSONObject result = hfPayHelper.getBalance(userHfExt);
        return result;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void verifyPay(UserInfo userInfo, Long id, String dealPassWord, String verifyCode, String token) {
        PayOrder payOrder = payOrderDao.getById(id);
        Assert.notNull(payOrder, () -> new GlobalRunTimeException(ErrorCode.ORDER_NOT_FOUND));
        Assert.isFalse(payOrder.getStatus() == PayStatusEnum.SUCCESS, () -> new GlobalRunTimeException(ErrorCode.ORDER_PAID));
        PayMethodEnum payType = payOrder.getPayType();
        String title = null;

        switch (payType) {
            case FAST_PAY:
                sandFastPayVerify(userInfo, verifyCode, payOrder, title);
                break;
            case WALLET_PAY:
                walletPayVerify(userInfo, dealPassWord, id, payOrder);
                break;
            case BALANCE_ONLY:
                balanceOnlyPayVerify(userInfo, dealPassWord, id, payOrder);
                break;
            case LL_PAY:
                llPayVerify(userInfo, id, token, verifyCode);
                break;
            case LL_BALANCE_PAY:
                llPayVerify(userInfo, id, token, verifyCode);
                break;
            case HNA_PAY:
                userHnaExtService.fastPayConfirm(payOrder, verifyCode);
                break;
            default:
                throw new GlobalRunTimeException("暂不支持该支持方式");
        }
    }

    private void balanceOnlyPayVerify(UserInfo userInfo, String dealPassWord, Long id, PayOrder payOrder) {
        // 增加判定,该用户必须是城市服务中心才可以使用
        if (BeanUtil.isEmpty(userCityServerCentreDao.getByUserId(userInfo.getId()))) {
            throw new GlobalRunTimeException("该账号无该支付方式使用权限");
        }
        Assert.notBlank(userInfo.getTransactionPassword(), () -> new GlobalRunTimeException("请先设置支付密码"));
        Assert.isTrue(StrUtil.equals(userInfo.getTransactionPassword(), dealPassWord), () -> new GlobalRunTimeException("支付密码不正确"));
        UserWallet userWallet = userWalletService.getByUserId(userInfo.getId());
        //提现余额
        BigDecimal balance = userWallet.getBalance();
        //支付余额
        BigDecimal payBalance = userWallet.getPayBalance();
        BigDecimal payAmount = payOrder.getPayAmount();
        BigDecimal sumBalance = balance.add(payBalance);
        Assert.isFalse(payAmount.compareTo(sumBalance) == 1, () -> new GlobalRunTimeException(ErrorCode.BALANCE_NO_ENOUGH));

        WalletDetailTypeEnum detailTypeEnum = null;
        switch (payOrder.getOrderType()) {
            case PAY_SALVAGE:
                detailTypeEnum = WalletDetailTypeEnum.ROUGH_STONE_PURCHASE;
                break;
            default:
                throw new GlobalRunTimeException("支付订单类型不正确");
        }
        // 必须走可提现余额支付,不走支付余额
        Assert.isTrue(userWalletService.subBalance(userWallet, payAmount, id, detailTypeEnum, UserBalanceTypeEnum.BALANCE), () -> new GlobalRunTimeException(ErrorCode.PAYMENT_FAILED));
        orderPaySuccess(payOrder, DateTime.now().toString(dateTimeFormat), null);
    }

    private void walletPayVerify(UserInfo userInfo, String dealPassword, Long id, PayOrder payOrder) {
        Assert.notBlank(userInfo.getTransactionPassword(), () -> new GlobalRunTimeException("请先设置支付密码"));
        Assert.isTrue(StrUtil.equals(userInfo.getTransactionPassword(), dealPassword), () -> new GlobalRunTimeException("支付密码不正确"));
        UserWallet userWallet = userWalletService.getByUserId(userInfo.getId());
        //提现余额
        BigDecimal balance = userWallet.getBalance();
        //支付余额
        BigDecimal payBalance = userWallet.getPayBalance();
        BigDecimal payAmount = payOrder.getPayAmount();
        BigDecimal sumBalance = balance.add(payBalance);
        Assert.isFalse(payAmount.compareTo(sumBalance) == 1, () -> new GlobalRunTimeException(ErrorCode.BALANCE_NO_ENOUGH));

        WalletDetailTypeEnum detailTypeEnum = null;
        switch (payOrder.getOrderType()) {
            case PAY:
                detailTypeEnum = WalletDetailTypeEnum.CONSUMPTION;
                break;
            case SECOND:
                detailTypeEnum = WalletDetailTypeEnum.SECOND_CONSUMPTION;
                break;
            case SECOND_EQUITY_PROPS:
                detailTypeEnum = WalletDetailTypeEnum.PROPS_SALES;
                break;
            case BUSINESS_CARD:
                detailTypeEnum = WalletDetailTypeEnum.BUSINESS_CARD;
                break;
            case SCROLL_BUY:
                detailTypeEnum = WalletDetailTypeEnum.WANT_BUY_SCROLL_PRE_PAY;
                break;
            case COLLECTIVE:
                detailTypeEnum = WalletDetailTypeEnum.COLLECTIVE_PAY;
                break;
            default:
                throw new GlobalRunTimeException("支付订单类型不正确");
        }
        if (payOrder.getOrderType() == PayTypeEnum.PAY) {
            if (payBalance.compareTo(payAmount) >= 0) { //如果支付账户足够 直接从支付账户扣
                payOrder.setPayBalanceAmount(payAmount);
                Assert.isTrue(userWalletService.otherSubBalance(userWallet, payAmount, id, detailTypeEnum, UserBalanceTypeEnum.PAY_BALANCE), () -> new GlobalRunTimeException(ErrorCode.PAYMENT_FAILED));
            } else {//如果支付账户没钱
                if (payBalance.compareTo(BigDecimal.ZERO) == 0) {//支付账户没钱,直接扣提现账户
                    Assert.isTrue(userWalletService.otherSubBalance(userWallet, payAmount, id, detailTypeEnum, UserBalanceTypeEnum.BALANCE), () -> new GlobalRunTimeException(ErrorCode.PAYMENT_FAILED));
                } else {//如果支付账户有钱 但是不够
                    //除支付账户
                    Assert.isTrue(userWalletService.otherSubBalance(userWallet, payBalance, id, detailTypeEnum, UserBalanceTypeEnum.PAY_BALANCE), () -> new GlobalRunTimeException(ErrorCode.PAYMENT_FAILED));
                    payOrder.setPayBalanceAmount(payBalance);
                    BigDecimal subtract = payAmount.subtract(payBalance);
                    Assert.isTrue(userWalletService.otherSubBalance(userWallet, subtract, id, detailTypeEnum, UserBalanceTypeEnum.BALANCE), () -> new GlobalRunTimeException(ErrorCode.PAYMENT_FAILED));
                    payOrder.setBalanceAmount(subtract);
                }
            }
        } else {
            if (payBalance.compareTo(payAmount) >= 0) { //如果支付账户足够 直接从支付账户扣
                payOrder.setPayBalanceAmount(payAmount);
                Assert.isTrue(userWalletService.subBalance(userWallet, payAmount, id, detailTypeEnum, UserBalanceTypeEnum.PAY_BALANCE), () -> new GlobalRunTimeException(ErrorCode.PAYMENT_FAILED));
            } else {//如果支付账户没钱
                if (payBalance.compareTo(BigDecimal.ZERO) == 0) {//支付账户没钱,直接扣提现账户
                    payOrder.setBalanceAmount(payAmount);
                    Assert.isTrue(userWalletService.subBalance(userWallet, payAmount, id, detailTypeEnum, UserBalanceTypeEnum.BALANCE), () -> new GlobalRunTimeException(ErrorCode.PAYMENT_FAILED));
                } else {//如果支付账户有钱 但是不够
                    //先扣除支付账户
                    Assert.isTrue(userWalletService.subBalance(userWallet, payBalance, id, detailTypeEnum, UserBalanceTypeEnum.PAY_BALANCE), () -> new GlobalRunTimeException(ErrorCode.PAYMENT_FAILED));
                    payOrder.setPayBalanceAmount(payBalance);
                    BigDecimal subtract = payAmount.subtract(payBalance);
                    Assert.isTrue(userWalletService.subBalance(userWallet, subtract, id, detailTypeEnum, UserBalanceTypeEnum.BALANCE), () -> new GlobalRunTimeException(ErrorCode.PAYMENT_FAILED));
                    payOrder.setBalanceAmount(subtract);
                }
            }
        }
        orderPaySuccess(payOrder, DateTime.now().toString(dateTimeFormat), null);
    }

    private void sandFastPayVerify(UserInfo userInfo, String verifyCode, PayOrder payOrder, String title) {
        Assert.notBlank(verifyCode, () -> new GlobalRunTimeException("请填写验证码"));
        boolean needSplit = Boolean.FALSE;
        switch (payOrder.getOrderType()) {
            case PAY:
                Order order = orderDao.getByOrderNo(payOrder.getOrderNo());
                Assert.notNull(order, () -> new GlobalRunTimeException(ErrorCode.ORDER_NOT_FOUND));
                Assert.isTrue(order.getUserId().longValue() == userInfo.getId().longValue(), () -> new GlobalRunTimeException(ErrorCode.ORDER_NOT_FOUND));
                Assert.isTrue(order.getStatus() == OrderStatusEnum.WAIT_PAY, () -> new GlobalRunTimeException(ErrorCode.ORDER_STATUS_ERROR));
                title = order.getFirstTitle();
                break;
            case SECOND:
                List<PayOrderItem> payOrderItems = payOrderItemDao.getByPayOrderId(payOrder.getId());
                for (PayOrderItem payOrderItem : payOrderItems) {
                    SecondOrder secondOrder = secondOrderDao.getById(payOrderItem.getOrderId());
                    Assert.notNull(secondOrder, () -> new GlobalRunTimeException(ErrorCode.ORDER_NOT_FOUND));
                    Assert.isTrue(secondOrder.getBuyUserId().longValue() == userInfo.getId().longValue(), () -> new GlobalRunTimeException(ErrorCode.ORDER_NOT_FOUND));
                    Assert.isTrue(secondOrder.getStatus() == OrderStatusEnum.WAIT_PAY, () -> new GlobalRunTimeException(ErrorCode.ORDER_STATUS_ERROR));
                    title = secondOrder.getFirstTitle();
                }
//                needSplit = true;
                break;
            case SCROLL_BUY:
                ScrollWantBuy scrollWantBuy = scrollWantBuyDao.getByOrderNo(payOrder.getOrderNo());
                Assert.notNull(scrollWantBuy, () -> new GlobalRunTimeException(ErrorCode.ORDER_NOT_FOUND));
                Assert.isTrue(scrollWantBuy.getShopUserId().longValue() == userInfo.getId().longValue(), () -> new GlobalRunTimeException(ErrorCode.ORDER_NOT_FOUND));
                Assert.isTrue(scrollWantBuy.getStatus() == WantBuyOrderStatusEnum.WAIT_PAY, () -> new GlobalRunTimeException(ErrorCode.ORDER_STATUS_ERROR));
                title = "求购预付款";
//                needSplit = true;
                break;
            case COLLECTIVE:
                payOrderItems = payOrderItemDao.getByPayOrderId(payOrder.getId());
                for (PayOrderItem payOrderItem : payOrderItems) {
                    CollectiveOrder collectiveOrder = collectiveOrderDao.getById(payOrderItem.getOrderId());
                    Assert.notNull(collectiveOrder, () -> new GlobalRunTimeException(ErrorCode.ORDER_NOT_FOUND));
                    Assert.isTrue(collectiveOrder.getBuyUserId().longValue() == userInfo.getId().longValue(), () -> new GlobalRunTimeException(ErrorCode.ORDER_NOT_FOUND));
                    Assert.isTrue(collectiveOrder.getStatus() == OrderStatusEnum.WAIT_PAY, () -> new GlobalRunTimeException(ErrorCode.ORDER_STATUS_ERROR));
                    title = collectiveOrder.getCollectionName();
                }
//                needSplit = true;
                break;
            case PAY_SALVAGE:
                RoughStoneOrder roughStoneOrder = roughStoneOrderDao.getByOrderNo(payOrder.getOrderNo());
                Assert.notNull(roughStoneOrder, () -> new GlobalRunTimeException(ErrorCode.ORDER_NOT_FOUND));
                Assert.isTrue(roughStoneOrder.getUserId().longValue() == userInfo.getId().longValue(), () -> new GlobalRunTimeException(ErrorCode.ORDER_NOT_FOUND));
                Assert.isTrue(roughStoneOrder.getStatus() == OrderStatusEnum.WAIT_PAY, () -> new GlobalRunTimeException(ErrorCode.ORDER_STATUS_ERROR));
                title = roughStoneOrder.getFirstTitle();
                break;
            case SECOND_EQUITY_PROPS:
                payOrderItems = payOrderItemDao.getByPayOrderId(payOrder.getId());
                for (PayOrderItem payOrderItem : payOrderItems) {
                    SecondEquityPropsOrder secondOrder = secondEquityPropsOrderDao.getById(payOrderItem.getOrderId());
                    Assert.notNull(secondOrder, () -> new GlobalRunTimeException(ErrorCode.ORDER_NOT_FOUND));
                    Assert.isTrue(secondOrder.getBuyUserId().longValue() == userInfo.getId().longValue(), () -> new GlobalRunTimeException(ErrorCode.ORDER_NOT_FOUND));
                    Assert.isTrue(secondOrder.getStatus() == OrderStatusEnum.WAIT_PAY, () -> new GlobalRunTimeException(ErrorCode.ORDER_STATUS_ERROR));
                    title = secondOrder.getFirstTitle();
                }
//                needSplit = true;
                break;
            case BUSINESS_CARD:
                BusinessCardOrder businessCardOrder = businessCardOrderDao.getByOrderNo(payOrder.getOrderNo());
                Assert.notNull(businessCardOrder, () -> new GlobalRunTimeException(ErrorCode.ORDER_NOT_FOUND));
                Assert.isTrue(businessCardOrder.getUserId().longValue() == userInfo.getId().longValue(), () -> new GlobalRunTimeException(ErrorCode.ORDER_NOT_FOUND));
                Assert.isTrue(businessCardOrder.getStatus() == OrderStatusEnum.WAIT_PAY, () -> new GlobalRunTimeException(ErrorCode.ORDER_STATUS_ERROR));
                title = businessCardOrder.getFirstTitle();
                break;
            default:
                throw new GlobalRunTimeException("支付订单类型不正确");
        }
        UserBankCard userBankCard = userBankCardDao.getById(payOrder.getUserCardId());
        Assert.notNull(userBankCard, () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
        Assert.isTrue(userBankCard.getUserId().longValue() == userInfo.getId().longValue(), () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
        JSONObject header = getHeader(PAY_METHOD, BIND_CARD);
        JSONObject body = getFastPayRequest(payOrder, title, userBankCard, userInfo, verifyCode, needSplit);
        JSONObject result = fastPayRequest(header, body, PAY_PATH);
        payOrderDao.updateWaitResult(body.toJSONString(), result.toJSONString(), payOrder.getId());
        if (!StrUtil.equals(result.getJSONObject("head").getString("respCode"), "000000")) {
            throw new GlobalRunTimeException("支付失败:" + result.getJSONObject("head").getString("respMsg"));
        }
    }


    @Override
    public Page<PayOrderPageDTO> payOrderPageFromAdmin(String orderNo, String tradeNo, String userTel, PayMethodEnum payType, PayChannelEnum channel, PayTypeEnum orderType, String bankCardNo, PayStatusEnum status, Date startPayTime, Date endPayTime, int pageNo, int pageSize) {
        Page<PayOrderPageDTO> payOrderPageDTOPage = payOrderDao.payOrderPageFromAdmin(orderNo, tradeNo, userTel, payType, channel, orderType, bankCardNo, status, startPayTime, endPayTime, pageNo, pageSize);
        return payOrderPageDTOPage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public GetPaySignVO getPayWantBuy(PayMethodEnum paymentMethod, Long orderId, Long bankCardId, UserInfo userInfo,
                                      String clientIP, String mac, Boolean webPay, Integer jumpType, String password, String randomKey) {
        ScrollWantBuy wantBuy = scrollWantBuyDao.getById(orderId);
        Assert.notNull(wantBuy, () -> new GlobalRunTimeException(ErrorCode.ORDER_NOT_FOUND));
        Assert.isTrue(wantBuy.getShopUserId().longValue() == userInfo.getId().longValue(), () -> new GlobalRunTimeException(ErrorCode.ORDER_NOT_FOUND));
        Assert.isTrue(wantBuy.getStatus() == WantBuyOrderStatusEnum.WAIT_PAY, () -> new GlobalRunTimeException(ErrorCode.ORDER_STATUS_ERROR));
        IdcardInfo idcardInfo = idcardInfoDao.getByUserIdAndIsPass(userInfo.getId());
        Assert.notNull(idcardInfo, () -> new GlobalRunTimeException(ErrorCode.USER_NOT_SM));
        Assert.isNull(payOrderDao.getPaySuccessByOrderNo(wantBuy.getOrderNo()), () -> new GlobalRunTimeException(ErrorCode.ORDER_PAID));
        // 杉德收银台支付的时候，不会重新发起一条，而是会直接告知错误信息订单已存在。所以要查询一下,确定是否存在,同时也要考虑是否过期的问题
        if (paymentMethod == PayMethodEnum.SAND_BALANCE_PAY) {
            PayOrder byOrderNo = payOrderDao.getByOrderNo(wantBuy.getOrderNo());
            if (BeanUtil.isNotEmpty(byOrderNo)) {
                if (byOrderNo.getStatus() == PayStatusEnum.INIT) {
                    GetPaySignVO getPaySignVO = new GetPaySignVO();
                    getPaySignVO.setSign(byOrderNo.getReqResult());
                    getPaySignVO.setId(byOrderNo.getId());
                    getPaySignVO.setOrderNo(wantBuy.getOrderNo());
                    getPaySignVO.setPayMethodEnum(paymentMethod);
                    return getPaySignVO;
                } else {
                    throw new GlobalRunTimeException("订单状态异常，取消后重新下单");
                }
            }
        }
        PayOrder payOrder = new PayOrder();
        DateTime now = DateTime.now();
        payOrder.setPayType(paymentMethod);
        payOrder.setReqTime(now);
        payOrder.setCloseTime(DateTime.now().offset(DateField.HOUR, 12));
        payOrder.setOrderNo(wantBuy.getOrderNo());
        payOrder.setReqIp(clientIP);
        payOrder.setUserCardId(bankCardId);
        payOrder.setUserId(userInfo.getId());
        payOrder.setOrderType(PayTypeEnum.SCROLL_BUY);
        payOrder.setPayAmount(wantBuy.getSumPrice());
        payOrder.setRefundAmount(BigDecimal.ZERO);
        payOrder.setChannel(paymentMethod.getChannel());
        payOrder.setStatus(PayStatusEnum.INIT);
        payOrder.setTradeNo(UUID.fastUUID().toString().replaceAll("-", ""));
        payOrder.setUserId(userInfo.getId());
        String sign = null;
        switch (paymentMethod) {
            case WALLET_PAY:
                break;
            case FAST_PAY: //衫德绑卡
                Assert.notNull(bankCardId, () -> new GlobalRunTimeException("请选择支付银行卡"));
                UserBankCard userBankCard = userBankCardDao.getById(bankCardId);
                Assert.isTrue(ObjectUtil.isNotNull(userBankCard) || userBankCard.getChannel() != PayChannelEnum.SAND, () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                Assert.isTrue(userBankCard.getUserId().longValue() == userInfo.getId().longValue(), () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                payOrder.setNotifyUrl(SandConfig.NOTIFY_URL);
                payOrder.setFrontUrl(SandConfig.FAST_RETURN_URL);
                JSONObject header = getHeader(PAY_SMS_METHOD, BIND_CARD);
                JSONObject body = getSendSmsRequest(userBankCard, userInfo, payOrder.getTradeNo());
                JSONObject result = fastPayRequest(header, body, PAY_SMS_PATH); //这里没错
                payOrder.setReqResult(result.toJSONString());
                if (!StrUtil.equals(result.getJSONObject("head").getString("respCode"), "000000")) {
                    throw new GlobalRunTimeException("发送短信失败：" + result.getJSONObject("head").getString("respMsg"));
                }
                break;
            case LL_PAY:
                Assert.notNull(bankCardId, () -> new GlobalRunTimeException("请选择支付银行卡"));
                userBankCard = userBankCardDao.getById(bankCardId);
                Assert.isTrue(ObjectUtil.isNotNull(userBankCard) || userBankCard.getChannel() != PayChannelEnum.LL_PAY, () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                Assert.isTrue(userBankCard.getUserId().longValue() == userInfo.getId().longValue(), () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                payOrder.setNotifyUrl(paySuccessNotifyUrl);
                payOrder.setFrontUrl(LlConfig.paySuccessReturnUrl + "?jump=page&type=1&orderNo=" + payOrder.getOrderNo());
                payOrder.setUserId(userInfo.getId());
                llPayHelper.createOrderForSecuredConsume(userInfo, payOrder, null, PayMethodEnum.LL_PAY);
                result = llPayHelper.fastPay(userInfo, "传奇卷轴" + wantBuy.getWantBuyCount() + "个", payOrder, userBankCard);
                payOrder.setReqResult(result.toJSONString());
                sign = result.getString("token");
                break;
            case LL_BALANCE_PAY:
                LlUserExt userExt = llUserExtService.getByUserId(userInfo.getId());
                Assert.isTrue(ObjectUtil.isNotNull(userExt) && userExt.getStatus() == AccountStatusEnum.SUCCESS, () -> new GlobalRunTimeException("请先完成连连开户"));
                Assert.notNull(password, () -> new GlobalRunTimeException("连连钱包密码不能为空"));
                payOrder.setNotifyUrl(paySuccessNotifyUrl);
                payOrder.setFrontUrl(LlConfig.paySuccessReturnUrl + "?jump=page&type=1&orderNo=" + payOrder.getOrderNo());
                payOrder.setUserId(userInfo.getId());
                //二级市场c2c使用担保交易避免二清
                llPayHelper.createOrderForSecuredConsume(userInfo, payOrder, userExt, PayMethodEnum.LL_BALANCE_PAY);
                result = llPayHelper.balancePay(userInfo, "传奇卷轴" + wantBuy.getWantBuyCount() + "个"
                        , payOrder, password, userExt, idcardInfo, randomKey);
                payOrder.setReqResult(result.toJSONString());
//                sign = result.getString("token");
                break;
            case HNA_PAY:
                Assert.notNull(bankCardId, () -> new GlobalRunTimeException("请选择支付银行卡"));
                userBankCard = userBankCardDao.getById(bankCardId);
                Assert.isTrue(
                        ObjectUtil.isNotNull(userBankCard) || userBankCard.getChannel() != PayChannelEnum.HNA_PAY,
                        () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                Assert.isTrue(
                        userBankCard.getUserId().longValue() == userInfo.getId().longValue(),
                        () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                HnaFastPayDTO dto = new HnaFastPayDTO();
                dto.setPayType("2");
                dto.setPayOrderNo(payOrder.getTradeNo());
                dto.setTranAmount(payOrder.getPayAmount().toPlainString());
                dto.setCardNo(userBankCard.getBankCardNo());
                dto.setIdentityCode(idcardInfo.getCardId());
                dto.setHolderName(idcardInfo.getName());
                dto.setIdentityType("1");
                dto.setMobileNo(userBankCard.getMobile());
                dto.setReceiveUserId(hnaConfig.getMerId());
                payOrder.setNotifyUrl(hnaConfig.getT007NotifyUrl());
                payOrder.setFrontUrl(LlConfig.paySuccessReturnUrl + "?jump=page&type=1&orderNo=" + payOrder.getOrderNo());
                result = userHnaExtService.fastPay(userInfo, dto);
                payOrder.setReqResult(result.toJSONString());
                payOrder.setOutTradeNo(result.getString("ncountOrderId"));
                break;
            case HF_FAST_PAY: //汇付绑卡
                payOrder.setNotifyUrl(HfConfig.notifyUrl);
                if (BooleanUtil.isTrue(webPay)) {
                    StringBuffer frontUrl = new StringBuffer();
                    if (jumpType.intValue() == 1) {
                        frontUrl.append(secondFrontReturnUrl);
                    } else if (jumpType.intValue() == 2) {
                        frontUrl.append(daoFrontReturnUrl);
                    }
                    frontUrl.append("?orderNo=").append(payOrder.getOrderNo()).append("&id=").append(orderId).append("&type=1");
                    payOrder.setFrontUrl(frontUrl.toString());
                } else {
                    payOrder.setFrontUrl(SandConfig.FAST_RETURN_URL);
                }
                IdcardInfo idCard = idcardInfoDao.getByUserIdAndIsPass(payOrder.getUserId());
                JSONObject jsonObject = hfPayHelper.createOrder(orderId, payOrder, "传奇卷轴" + wantBuy.getWantBuyCount() + "个", null, idCard.getCardId(), idCard.getName(), payOrder.getReqIp(), mac, false);
                sign = jsonObject.getString("pay_url");
                payOrder.setReqResult(jsonObject.toJSONString());
                break;
            case SAND_BALANCE_PAY: //衫德余额
                if (!userInfo.getSandAccountOpen()) {
                    throw new GlobalRunTimeException("请先完成开户");
                }
                BalanceVO balance = sandAccountHelper.getBalance(userInfo);
                if (NumberUtil.isGreater(payOrder.getPayAmount(), new BigDecimal(balance.getAvailableBal()))) {
                    throw new GlobalRunTimeException("余额不足");
                }
                payOrder.setNotifyUrl(SandConfig.NOTIFY_URL);
                if (webPay) {
                    StringBuffer frontUrl = new StringBuffer();
                    if (jumpType.intValue() == 1) {
                        frontUrl.append(walletUrl);
                    } else if (jumpType.intValue() == 2) {
                        frontUrl.append(daoFrontReturnUrl);
                    }
                    frontUrl.append("?orderNo=").append(payOrder.getOrderNo()).append("&id=").append(orderId).append("&type=1");
                    payOrder.setFrontUrl(frontUrl.toString());
                } else {
                    payOrder.setFrontUrl(SandConfig.FAST_RETURN_URL);
                }
                sign = SandPayUtil.c2bRequest(getHeader(C2B_METHOD, C2B_PRODUCT_CODE), c2bCreateOrder(payOrder, "传奇卷轴" + wantBuy.getWantBuyCount() + "个", userInfo), "createOrder");
                payOrder.setReqResult(sign);
                break;
            default:
                throw new GlobalRunTimeException("暂不支持该支付方式");
        }
        payOrder.insert();
        GetPaySignVO getPaySignVO = new GetPaySignVO();
        getPaySignVO.setSign(sign);
        getPaySignVO.setId(payOrder.getId());
        getPaySignVO.setOrderNo(wantBuy.getOrderNo());
        getPaySignVO.setPayMethodEnum(paymentMethod);
        return getPaySignVO;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public GetPaySignVO getPayCollective(PayMethodEnum paymentMethod, List<Long> orderIds, Long bankCardId, UserInfo userInfo,
                                         String clientIP, String mac, Boolean webPay, Integer jumpType, String password, String randomKey) {
        List<CollectiveOrder> userWaitPayOrderBuyIds = collectiveOrderDao.getUserWaitPayOrderBuyIds(userInfo.getId(), orderIds);
        Assert.isTrue(userWaitPayOrderBuyIds.size() == orderIds.size(), () -> new GlobalRunTimeException("订单状态发生改变，请刷新后再试"));
        Assert.notEmpty(userWaitPayOrderBuyIds, () -> new GlobalRunTimeException(ErrorCode.ORDER_NOT_FOUND));
        IdcardInfo idcardInfo = idcardInfoDao.getByUserIdAndIsPass(userInfo.getId());
        Assert.notNull(idcardInfo, () -> new GlobalRunTimeException(ErrorCode.USER_NOT_SM));
        // 杉德收银台支付的时候，不会重新发起一条，而是会直接告知错误信息订单已存在。所以要查询一下,确定是否存在,同时也要考虑是否过期的问题
        if (paymentMethod == PayMethodEnum.SAND_BALANCE_PAY) {
            PayOrder byOrderNo = payOrderDao.getByOrderNo(userWaitPayOrderBuyIds.get(0).getOrderNo());
            if (BeanUtil.isNotEmpty(byOrderNo)) {
                if (byOrderNo.getStatus() == PayStatusEnum.INIT) {
                    GetPaySignVO getPaySignVO = new GetPaySignVO();
                    getPaySignVO.setSign(byOrderNo.getReqResult());
                    getPaySignVO.setId(byOrderNo.getId());
                    getPaySignVO.setOrderNo(userWaitPayOrderBuyIds.get(0).getOrderNo());
                    getPaySignVO.setPayMethodEnum(paymentMethod);
                    return getPaySignVO;
                } else {
                    throw new GlobalRunTimeException("订单状态异常，取消后重新下单");
                }
            }
        }
        BigDecimal sumPrice = userWaitPayOrderBuyIds.stream().map(CollectiveOrder::getBuyPrice).reduce(BigDecimal::add).get();
        PayOrder payOrder = new PayOrder();
        DateTime now = DateTime.now();
        payOrder.setPayType(paymentMethod);
        payOrder.setReqTime(now);
        payOrder.setCloseTime(DateTime.now().offset(DateField.MINUTE, 3));
        payOrder.setOrderNo(userWaitPayOrderBuyIds.get(0).getOrderNo());
        payOrder.setReqIp(clientIP);
        payOrder.setUserCardId(bankCardId);
        payOrder.setUserId(userInfo.getId());
        payOrder.setOrderType(PayTypeEnum.COLLECTIVE);
        payOrder.setPayAmount(sumPrice);
        payOrder.setRefundAmount(BigDecimal.ZERO);
        payOrder.setChannel(paymentMethod.getChannel());
        payOrder.setStatus(PayStatusEnum.INIT);
        payOrder.setTradeNo(UUID.fastUUID().toString().replaceAll("-", ""));
        payOrder.setUserId(userInfo.getId());
        String sign = null;
        switch (paymentMethod) {
            case WALLET_PAY:
                break;
            case FAST_PAY: //衫德绑卡
                Assert.notNull(bankCardId, () -> new GlobalRunTimeException("请选择支付银行卡"));
                UserBankCard userBankCard = userBankCardDao.getById(bankCardId);
                Assert.isTrue(ObjectUtil.isNotNull(userBankCard) || userBankCard.getChannel() != PayChannelEnum.SAND, () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                Assert.isTrue(userBankCard.getUserId().longValue() == userInfo.getId().longValue(), () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                payOrder.setNotifyUrl(SandConfig.NOTIFY_URL);
                payOrder.setFrontUrl(SandConfig.FAST_RETURN_URL);
                JSONObject header = getHeader(PAY_SMS_METHOD, BIND_CARD);
                JSONObject body = getSendSmsRequest(userBankCard, userInfo, payOrder.getTradeNo());
                JSONObject result = fastPayRequest(header, body, PAY_SMS_PATH); //这里没错
                payOrder.setReqResult(result.toJSONString());
                if (!StrUtil.equals(result.getJSONObject("head").getString("respCode"), "000000")) {
                    throw new GlobalRunTimeException("发送短信失败：" + result.getJSONObject("head").getString("respMsg"));
                }
                break;
            case LL_PAY:
                Assert.notNull(bankCardId, () -> new GlobalRunTimeException("请选择支付银行卡"));
                userBankCard = userBankCardDao.getById(bankCardId);
                Assert.isTrue(ObjectUtil.isNotNull(userBankCard) || userBankCard.getChannel() != PayChannelEnum.LL_PAY, () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                Assert.isTrue(userBankCard.getUserId().longValue() == userInfo.getId().longValue(), () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                payOrder.setNotifyUrl(paySuccessNotifyUrl);
                payOrder.setFrontUrl(LlConfig.paySuccessReturnUrl + "?jump=page&type=1&orderNo=" + payOrder.getOrderNo());
                payOrder.setUserId(userInfo.getId());
                llPayHelper.createOrderForSecuredConsume(userInfo, payOrder, null, PayMethodEnum.LL_PAY);
                result = llPayHelper.fastPay(userInfo, userWaitPayOrderBuyIds.get(0).getCollectionName(), payOrder, userBankCard);
                payOrder.setReqResult(result.toJSONString());
                sign = result.getString("token");
                break;
            case LL_BALANCE_PAY:
                LlUserExt userExt = llUserExtService.getByUserId(userInfo.getId());
                Assert.isTrue(ObjectUtil.isNotNull(userExt) && userExt.getStatus() == AccountStatusEnum.SUCCESS, () -> new GlobalRunTimeException("请先完成连连开户"));
                Assert.notNull(password, () -> new GlobalRunTimeException("连连钱包密码不能为空"));
                payOrder.setNotifyUrl(paySuccessNotifyUrl);
                payOrder.setFrontUrl(LlConfig.paySuccessReturnUrl + "?jump=page&type=1&orderNo=" + payOrder.getOrderNo());
                payOrder.setUserId(userInfo.getId());
                //二级市场c2c使用担保交易避免二清
                llPayHelper.createOrderForSecuredConsume(userInfo, payOrder, userExt, PayMethodEnum.LL_BALANCE_PAY);
                result = llPayHelper.balancePay(userInfo, userWaitPayOrderBuyIds.get(0).getCollectionName()
                        , payOrder, password, userExt, idcardInfo, randomKey);
                payOrder.setReqResult(result.toJSONString());
                sign = result.getString("token");
                break;
            case HNA_PAY:
                Assert.notNull(bankCardId, () -> new GlobalRunTimeException("请选择支付银行卡"));
                userBankCard = userBankCardDao.getById(bankCardId);
                Assert.isTrue(
                        ObjectUtil.isNotNull(userBankCard) || userBankCard.getChannel() != PayChannelEnum.HNA_PAY,
                        () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                Assert.isTrue(
                        userBankCard.getUserId().longValue() == userInfo.getId().longValue(),
                        () -> new GlobalRunTimeException(ErrorCode.CARD_NOT_FOUND));
                HnaFastPayDTO dto = new HnaFastPayDTO();
                dto.setPayType("2");
                dto.setPayOrderNo(payOrder.getTradeNo());
                dto.setTranAmount(payOrder.getPayAmount().toPlainString());
                dto.setCardNo(userBankCard.getBankCardNo());
                dto.setIdentityCode(idcardInfo.getCardId());
                dto.setHolderName(idcardInfo.getName());
                dto.setIdentityType("1");
                dto.setMobileNo(userBankCard.getMobile());
                dto.setReceiveUserId(hnaConfig.getMerId());
                payOrder.setNotifyUrl(hnaConfig.getT007NotifyUrl());
                payOrder.setFrontUrl(LlConfig.paySuccessReturnUrl + "?jump=page&type=1&orderNo=" + payOrder.getOrderNo());
                result = userHnaExtService.fastPay(userInfo, dto);
                payOrder.setReqResult(result.toJSONString());
                payOrder.setOutTradeNo(result.getString("ncountOrderId"));
                break;
            case HF_FAST_PAY: //汇付绑卡
                throw new GlobalRunTimeException("功能已下线");
            case SAND_BALANCE_PAY: //衫德余额
                if (!userInfo.getSandAccountOpen()) {
                    throw new GlobalRunTimeException("请先完成开户");
                }
                BalanceVO balance = sandAccountHelper.getBalance(userInfo);
                if (NumberUtil.isGreater(payOrder.getPayAmount(), new BigDecimal(balance.getAvailableBal()))) {
                    throw new GlobalRunTimeException("余额不足");
                }
                payOrder.setNotifyUrl(SandConfig.NOTIFY_URL);
                if (webPay) {
                    StringBuffer frontUrl = new StringBuffer();
                    if (jumpType.intValue() == 1) {
                        frontUrl.append(walletUrl);
                    } else if (jumpType.intValue() == 2) {
                        frontUrl.append(daoFrontReturnUrl);
                    }
                    frontUrl.append("?orderNo=").append(payOrder.getOrderNo()).append("&type=1");
                    payOrder.setFrontUrl(frontUrl.toString());
                } else {
                    payOrder.setFrontUrl(SandConfig.FAST_RETURN_URL);
                }
                sign = SandPayUtil.c2bRequest(getHeader(C2B_METHOD, C2B_PRODUCT_CODE), c2bCreateOrder(payOrder, userWaitPayOrderBuyIds.get(0).getCollectionName(), userInfo), "createOrder");
                payOrder.setReqResult(sign);
                break;
            default:
                throw new GlobalRunTimeException("暂不支持该支付方式");
        }
        payOrder.insert();
        for (CollectiveOrder collectiveOrder : userWaitPayOrderBuyIds) {
            PayOrderItem payOrderItem = new PayOrderItem();
            payOrderItem.setPayOrderId(payOrder.getId());
            payOrderItem.setOrderId(collectiveOrder.getId());
            payOrderItem.setOrderType(SecondPayOrderItemTypeEnum.COLLECTION);
            payOrderItem.setAmount(collectiveOrder.getBuyPrice());
            payOrderItem.insert();
        }
        GetPaySignVO getPaySignVO = new GetPaySignVO();
        getPaySignVO.setSign(sign);
        getPaySignVO.setId(payOrder.getId());
        getPaySignVO.setOrderNo(userWaitPayOrderBuyIds.get(0).getOrderNo());
        getPaySignVO.setPayMethodEnum(paymentMethod);
        return getPaySignVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void applePay(Long orderId, String receiptData, String isSandBox, String IP) throws GlobalException {
        Order order = orderDao.getById(orderId);
        //todo 保证pay_order只有一条
        PayOrder byTradeNo = payOrderDao.getByTradeNo(order.getOrderNo());
        if (ObjectUtil.isEmpty(byTradeNo)) {
            PayOrder payOrder = new PayOrder();
            DateTime now = DateTime.now();
            payOrder.setPayType(PayMethodEnum.APPLE_PAY);
            payOrder.setReqTime(now);
            payOrder.setCloseTime(order.getCloseTime());
            payOrder.setOrderNo(order.getOrderNo());
            payOrder.setReqIp(IP);
            payOrder.setOrderType(PayTypeEnum.PAY);
            payOrder.setPayAmount(order.getProductPrice());
            payOrder.setRefundAmount(BigDecimal.ZERO);
            payOrder.setTradeNo(UUID.fastUUID().toString().replaceAll("-", ""));
            payOrder.setChannel(PayMethodEnum.APPLE_PAY.getChannel());
            payOrder.setPayTime(now);
            payOrder.setPayResult(receiptData);
            payOrder.setNotifyUrl(getUrl());
            payOrder.setUserId(order.getUserId());
            String json = parseReceiptData(receiptData);
            if (StrUtil.isBlank(json)) {
                //todo 苹果服务器异常  定时任务去调用  查询sc_pay_order  status = PayStatusEnum.INIT  PayType=PayMethodEnum.APPLE_PAY 的订单
                payOrder.setStatus(PayStatusEnum.INIT);
                payOrder.insert();
            } else {
                JSONObject jsonObject = JSONObject.parseObject(json);
                String status = jsonObject.get("status").toString();
                if ("0".equals(status)) {
                    payOrder.setStatus(PayStatusEnum.SUCCESS);
                    payOrder.setReqResult(json);
                    payOrder.insert();
                    orderService.paySuccess(payOrder.getOrderNo());
                } else {
                    throw new GlobalRunTimeException(ErrorCode.PARAM_ERROR);
                }
            }
        } else {
            if (byTradeNo.getStatus() == PayStatusEnum.SUCCESS) {
                throw new GlobalRunTimeException("已完成交易,请勿重复提交");
            } else {
                throw new GlobalRunTimeException("订单正在处理,请勿重复提交");
            }
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void orderPaySuccess(PayOrder payOrder, String payTime, String result) {
        Assert.notNull(payOrder, () -> new GlobalRunTimeException(ErrorCode.ORDER_NOT_FOUND));
        if (payOrder.getStatus() == PayStatusEnum.SUCCESS) {
            return;
        }
        PayMethodEnum receiveType;
        if (payOrder.getChannel().equals(PayChannelEnum.LL_PAY)) {
            receiveType = PayMethodEnum.LL_BALANCE_PAY;
        } else {
            receiveType = PayMethodEnum.WALLET_PAY;
        }
        if (payOrder.getOrderType() == PayTypeEnum.PAY) {
            Order order = orderDao.getByOrderNo(payOrder.getOrderNo());
            RLock lock = redisson.getLock(RedisKeyEnum.STOCK_FREEZE_ID_ + order.getRelationId().toString());
            try {
                boolean b = lock.tryLock(30, TimeUnit.SECONDS);
                if (b) {
                    orderService.paySuccess(payOrder.getOrderNo());
                }
            } catch (InterruptedException e) {
                log.error("库存释放等待超时");
                throw new GlobalRunTimeException(ErrorCode.THE_SYSTEM_IS_BUSY_PLEASE_TRY_AGAIN_LATER);
            } finally {
                lock.unlock();
            }
        } else if (payOrder.getOrderType() == PayTypeEnum.RECHARGE) {
            throw new GlobalRunTimeException("功能已下线");
        } else if (payOrder.getOrderType() == PayTypeEnum.SECOND) {
            List<PayOrderItem> byPayOrderId = payOrderItemDao.getByPayOrderId(payOrder.getId());
            List<SecondOrder> secondOrders = secondOrderDao.listByIds(byPayOrderId.stream().map(PayOrderItem::getOrderId).collect(Collectors.toList()));
            //TODO 循环设置收款方式(根据支付方式) 6.3.6-pay
            secondOrders.forEach(s -> {
                s.setReceiveType(receiveType);
            });
            newSecondCollectionCommonService.paySuccess(secondOrders);
            if (payOrder.getChannel() == PayChannelEnum.HF_PAY) {
                JSONObject jsonObject = JSONObject.parseObject(result);
                HfTrans hfTrans = new HfTrans();
                hfTrans.setPayOrderId(payOrder.getId());
                hfTrans.setPayType(jsonObject.getString("pay_type"));
                hfTrans.setSumTransAmount(jsonObject.getBigDecimal("real_trans_amt"));
                hfTrans.setAlreadyTransAmount(BigDecimal.ZERO);
                hfTrans.setLastTransAmount(jsonObject.getBigDecimal("real_trans_amt"));
                hfTrans.setStatus(true);
                hfTrans.insert();
            }
        } else if (payOrder.getOrderType() == PayTypeEnum.COLLECTIVE) {
            List<PayOrderItem> byPayOrderId = payOrderItemDao.getByPayOrderId(payOrder.getId());
            List<CollectiveOrder> collectiveOrders = collectiveOrderDao.listByIds(byPayOrderId.stream().map(PayOrderItem::getOrderId).collect(Collectors.toList()));
            collectiveOrders.forEach(s -> {
                s.setReceiveType(receiveType);
            });
            collectiveOrderService.paySuccess(collectiveOrders);

        } else if (payOrder.getOrderType() == PayTypeEnum.PAY_SALVAGE) {

            RoughStoneOrder order = roughStoneOrderDao.getByOrderNo(payOrder.getOrderNo());
            RLock lock = redisson.getLock(RedisKeyEnum.ROUGH_STONE_PAYMENT_CALLBACK + order.getCollectionId().toString());
            try {
                boolean b = lock.tryLock(30, TimeUnit.SECONDS);
                if (b) {
                    roughStoneOrderService.paySuccess(order);
                }
            } catch (InterruptedException e) {
                log.error("库存释放等待超时");
            } finally {
                lock.unlock();
            }
        } else if (payOrder.getOrderType() == PayTypeEnum.SECOND_EQUITY_PROPS) {
            List<PayOrderItem> byPayOrderId = payOrderItemDao.getByPayOrderId(payOrder.getId());
            secondEquityPropsOrderService.paySuccess(payOrder, byPayOrderId.stream().map(PayOrderItem::getOrderId).collect(Collectors.toList()));
        } else if (payOrder.getOrderType() == PayTypeEnum.BUSINESS_CARD) {
            BusinessCardOrder order = businessCardOrderDao.getByOrderNo(payOrder.getOrderNo());
            businessCardOrderService.paySuccess(order);
        } else if (payOrder.getOrderType() == PayTypeEnum.SCROLL_BUY) {
            ScrollWantBuy wantBuy = scrollWantBuyDao.getByOrderNo(payOrder.getOrderNo());
            if (ObjectUtil.isNull(wantBuy) || wantBuy.getStatus() != WantBuyOrderStatusEnum.WAIT_PAY) {
                throw new GlobalRunTimeException("未找到支付订单");
            }
            if (wantBuy.getStatus() != WantBuyOrderStatusEnum.WAIT_PAY) {
                throw new GlobalRunTimeException("订单状态不正确");
            }
            wantBuy.setStatus(WantBuyOrderStatusEnum.IN_BUY);
            wantBuy.updateById();
        }
        payOrder.setStatus(PayStatusEnum.SUCCESS);
        payOrder.setPayTime(DateTime.of(payTime, dateTimeFormat));
        payOrder.setPayResult(result);
        payOrder.updateById();
    }


    @Override
    public void hfOpenNotify(String userKey, String userCustId, String acctId) throws GlobalException {
        UserHfExt userHfExt = userHfExtDao.findByUserKey(userKey);
        userHfExt.setUserCustId(userCustId);
        userHfExt.setAcctId(acctId);
        userHfExt.setStatus(AccountStatusEnum.SUCCESS);
        userHfExt.updateById();
        SaasTaskBurialPointDTO saasTaskBurialPointDTO = new SaasTaskBurialPointDTO();
        // 开户成功之后,发送任务判定
        messageQueueHelper.sendMessage(MessageTopic.DISK_TAKER, saasTaskBurialPointDTO.wallet(userHfExt.getUserId(), SaasTaskTypeEnum.OPEN_WALLET_FOR_THE_FIRST_TIME, BigDecimal.ONE, 1, null), SaasTaskTypeEnum.OPEN_WALLET_FOR_THE_FIRST_TIME.name());
        // 开户成功之后,发送任务判定
        messageQueueHelper.sendMessage(MessageTopic.DISK_TAKER, saasTaskBurialPointDTO.wallet(userHfExt.getUserId(), SaasTaskTypeEnum.FIRST_TIME_OPEN_WALLET_INVITATION, BigDecimal.ONE, 1, null), SaasTaskTypeEnum.FIRST_TIME_OPEN_WALLET_INVITATION.name());

    }

    @Override
    public Boolean getPayOrderStatus(String orderNo) {
        return ObjectUtil.isNotNull(payOrderDao.getPaySuccessByOrderNo(orderNo));
    }

    public String parseReceiptData(String receiptData) {
        String url = getUrl();
        JSONObject param = new JSONObject();
        param.put("receipt-data", receiptData);
        try {
            String json = HttpUtil.post(url, param.toJSONString());
            return json;
        } catch (Exception e) {
            log.warn("苹果服务器异常", e);
            return null;
        }
    }

    private String getUrl() {

        String isSandBox = staticDataDao.getByType("is_sand_box").getValue();

        String url = "";
        if ("1".equals(isSandBox)) {
            url = "https://sandbox.itunes.apple.com/verifyReceipt";

        } else if ("0".equals(isSandBox)) {
            url = "https://buy.itunes.apple.com/verifyReceipt";
        }
        log.info("苹果内购URL:{}", url);
        return url;
    }
}
